From 93b3b563735f77dfe0d85d2d6c9d2a9aa6326b9f Mon Sep 17 00:00:00 2001 From: fand Date: Tue, 11 Jun 2024 23:13:28 -0700 Subject: [PATCH] feat: use OffscreenCanvas for better quality and performance --- packages/react-vfx/src/dom-to-canvas.ts | 28 +++++++++++++------------ packages/react-vfx/src/vfx-player.ts | 8 +++++-- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/react-vfx/src/dom-to-canvas.ts b/packages/react-vfx/src/dom-to-canvas.ts index cc7dd90..a7d14e1 100644 --- a/packages/react-vfx/src/dom-to-canvas.ts +++ b/packages/react-vfx/src/dom-to-canvas.ts @@ -28,19 +28,18 @@ function cloneNode(node: T): T { export default function getCanvasFromElement( element: HTMLElement, originalOpacity: number, - oldCanvas?: HTMLCanvasElement, -): Promise { + oldCanvas?: OffscreenCanvas, +): Promise { const rect = element.getBoundingClientRect(); - const width = Math.max(rect.width * 1.01, rect.width + 1); // XXX - const height = Math.max(rect.height * 1.01, rect.height + 1); const ratio = window.devicePixelRatio; + const width = rect.width * ratio; + const height = rect.height * ratio; - const canvas = oldCanvas || document.createElement("canvas"); - canvas.width = width * ratio; - canvas.height = height * ratio; - canvas.style.width = width + "px"; - canvas.style.height = height + "px"; + const canvas = + oldCanvas && oldCanvas.width === width && oldCanvas.height === height + ? oldCanvas + : new OffscreenCanvas(width, height); // Clone element with styles in text attribute // to apply styles in SVG @@ -52,19 +51,22 @@ export default function getCanvasFromElement( const html = newElement.outerHTML; const xml = convertHtmlToXml(html); const svg = - `` + + `` + `${xml}`; return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { - const ctx = canvas.getContext("2d"); + const ctx = canvas.getContext( + "2d", + ) as OffscreenCanvasRenderingContext2D | null; if (ctx === null) { return reject(); } - ctx.clearRect(0, 0, canvas.width, canvas.height); + + ctx.clearRect(0, 0, width, height); ctx.scale(ratio, ratio); - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + ctx.drawImage(img, 0, 0, width, height); ctx.setTransform(1, 0, 0, 1, 0, 0); resolve(canvas); diff --git a/packages/react-vfx/src/vfx-player.ts b/packages/react-vfx/src/vfx-player.ts index 6db415f..c3d4705 100644 --- a/packages/react-vfx/src/vfx-player.ts +++ b/packages/react-vfx/src/vfx-player.ts @@ -159,9 +159,13 @@ export default class VFXPlayer { try { const oldTexture: THREE.CanvasTexture = e.uniforms["src"].value; - const canvas = oldTexture.image; + const oldCanvas = oldTexture.image; - await dom2canvas(e.element, e.originalOpacity, canvas); + const canvas = await dom2canvas( + e.element, + e.originalOpacity, + oldCanvas, + ); if (canvas.width === 0 || canvas.width === 0) { throw "omg"; }