Skip to content
New issue

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

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

Already on GitHub? # 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.

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

No branches or pull requests

2 participants