Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering onto an OffscreenCanvas using Web Workers #153

Open
isaac-nls opened this issue Apr 6, 2023 · 3 comments
Open

Rendering onto an OffscreenCanvas using Web Workers #153

isaac-nls opened this issue Apr 6, 2023 · 3 comments

Comments

@isaac-nls
Copy link

Hi,

I have a number of fairly high refresh rate charts all being rendered at once. To take pressure off the main thread, I was wondering if I could use web workers to offload the rendering.

Below is the code that I've tried so far. As you can see, I had to mock the window object and the getAttribute() calls for height and width. I'm now facing an error: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The image source is detached, which I understand to mean that no frame is ready to draw.

Any insights would be greatly appreciated.

<!-- src/components/SmoothieChart.vue -->
<template>
  <div>
    <canvas ref="onscreenCanvas" :width="width" :height="height"></canvas>
  </div>
</template>

<script>
import { onMounted, ref } from 'vue';
import Smoothie from 'smoothie';

export default {
  props: {
    width: {
      type: Number,
      required: true,
    },
    height: {
      type: Number,
      required: true,
    },
  },
  setup(props) {
    const onscreenCanvas = ref(null);

    onMounted(() => {
      const offscreenCanvas = new OffscreenCanvas(props.width, props.height);
      const worker = new Worker(new URL('./smoothieWorker.js', import.meta.url));
      worker.postMessage({ offscreenCanvas }, [offscreenCanvas]);

      const ctx = onscreenCanvas.value.getContext('2d');

      worker.onmessage = (event) => {
        if (event.data.type === 'frameReady') {
          ctx.drawImage(offscreenCanvas, 0, 0);
        }
      };
    });

    return { onscreenCanvas };
  },
};
</script>
// src/components/smoothieWorker.js
self.window = self;
importScripts('https://cdn.jsdelivr.net/npm/smoothie@1.37.0/smoothie.js');

self.addEventListener('message', (event) => {
  const { offscreenCanvas } = event.data;
  createSmoothieChart(offscreenCanvas);
});

function createSmoothieChart(offscreenCanvas) {
  const smoothieChart = new Smoothie.SmoothieChart({
    grid: { strokeStyle: 'rgba(255, 255, 255, 0.1)', lineWidth: 1 },
    labels: { fillStyle: 'rgba(255, 255, 255, 0.8)' },
    millisPerPixel: 20,
    responsive: true,
  });

  const timeSeries = new Smoothie.TimeSeries();
  smoothieChart.addTimeSeries(timeSeries, { lineWidth: 2, strokeStyle: 'rgb(0, 255, 0)' });

  smoothieChart.streamTo(offscreenCanvas, 1000 / 60);

  setInterval(() => {
    timeSeries.append(new Date().getTime(), Math.random() * 100);
    self.postMessage({ type: 'frameReady' }); // Send a message back when a frame is ready
  }, 1000);
}
@WofWca
Copy link
Collaborator

WofWca commented Apr 6, 2023

Have you managed to make it work without smoothie?

@isaac-nls
Copy link
Author

isaac-nls commented Apr 6, 2023 via email

@WofWca
Copy link
Collaborator

WofWca commented Apr 6, 2023

I mean try commenting out the smoothie code above and see if the setup works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants