Open Awendel opened 2 years ago
The library still depends on DOM layout and style resolution/computed values, which need to be done on the main thread.
Sure sure, but all of that data can be quite easily string encoded in a pre-step.
My suggested Pipeline:
MAIN-THREAD • get HTML Elements (.outerHTML etc) • get Computed Style & Text encode --> just convert to array or key value Map • send to Web Worker
WEB-WORKER • use XML parser to make sense of .outerHTML • translate the Computed Style Array / Map into ContextCommands • apply to OffscreenCanvas
This new structure might introduce some additional internal steps, but would in the end lead to much better performance
EDIT: Unless the majority of latency comes from getting the computedStyle etc instead of the Canvas Calls, haven't run a benchmark yet around that...
I thought I where drawing an image from document.body to an offscreenCanvas to use it as "colorPicker", but logging in a mutationObserver showed, that in older versions html2canvas appends and removes an iFrame on each mutation, newer version a DIV and an IMG. Is there any way to directly write to the offscreenCanvas? As I rerender on every mutation it can become rather "tricky"
This is my current class:
export class BodyToCanvas {
constructor() {
this.isRendering = false;
this.offscreenCanvas = document.createElement('canvas');
this.offscreenCtx = this.offscreenCanvas.getContext('2d', {
willReadFrequently: true,
});
}
renderBodyToCanvas() {
if (this.isRendering) return;
this.isRendering = true;
html2canvas(document.body, {
backgroundColor: 'transparent',
scale: 1,
logging: false, // Disable logging
}).then((bodyCanvas) => {
const { width, height } = bodyCanvas;
this.offscreenCanvas.width = width;
this.offscreenCanvas.height = height;
this.offscreenCtx.drawImage(bodyCanvas, 0, 0);
this.isRendering = false;
});
}
}
One big downside to this library is that it is blocking the main thread and can be quite slow when rendering a large amount of HTML.
What would be ideal is to expose an OffscreenCanvas API where for example if all styles are inline (not relying on a stylesheet), one just sends the entire outerHTML as a string blob to the web worker, that then uses an XML Parser etc. to convert it into Canvas rendering Calls.
This way a huge amount of HTML could be rendered to Canvas without blocking the MainThread at all.