Skip to content

Commit

Permalink
feat: use OffscreenCanvas for better quality and performance
Browse files Browse the repository at this point in the history
  • Loading branch information
fand committed Jun 12, 2024
1 parent 11aa413 commit 93b3b56
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 15 deletions.
28 changes: 15 additions & 13 deletions packages/react-vfx/src/dom-to-canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,18 @@ function cloneNode<T extends Node>(node: T): T {
export default function getCanvasFromElement(
element: HTMLElement,
originalOpacity: number,
oldCanvas?: HTMLCanvasElement,
): Promise<HTMLCanvasElement> {
oldCanvas?: OffscreenCanvas,
): Promise<OffscreenCanvas> {
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
Expand All @@ -52,19 +51,22 @@ export default function getCanvasFromElement(
const html = newElement.outerHTML;
const xml = convertHtmlToXml(html);
const svg =
`<svg xmlns="http://www.w3.org/2000/svg" width="${canvas.width}" height="${canvas.height}">` +
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">` +
`<foreignObject width="100%" height="100%">${xml}</foreignObject></svg>`;

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);
Expand Down
8 changes: 6 additions & 2 deletions packages/react-vfx/src/vfx-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Expand Down

0 comments on commit 93b3b56

Please sign in to comment.