2024-11-24 18:59:11 -05:00
|
|
|
import React, {useCallback, useEffect, useState} from "react";
|
2024-11-24 00:06:22 -05:00
|
|
|
import {useColorMode} from "@docusaurus/theme-common";
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
width: number;
|
|
|
|
height: number;
|
2024-11-24 18:59:11 -05:00
|
|
|
painter: Iterator<ImageData>;
|
2024-11-24 00:06:22 -05:00
|
|
|
children?: React.ReactNode;
|
|
|
|
}
|
2024-11-24 18:59:11 -05:00
|
|
|
export default function Canvas({width, height, painter, children}: Props) {
|
|
|
|
const {colorMode} = useColorMode();
|
|
|
|
const [image, setImage] = useState<[ImageData]>(null);
|
|
|
|
|
|
|
|
const [canvasCtx, setCanvasCtx] = useState<CanvasRenderingContext2D>(null);
|
2024-11-24 00:06:22 -05:00
|
|
|
const canvasRef = useCallback(node => {
|
|
|
|
if (node !== null) {
|
|
|
|
setCanvasCtx(node.getContext("2d"));
|
|
|
|
}
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const paintImage = new ImageData(width, height);
|
2024-11-24 18:59:11 -05:00
|
|
|
const paint = () => {
|
|
|
|
if (!canvasCtx || !image) {
|
2024-11-24 00:06:22 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-11-24 18:59:11 -05:00
|
|
|
for (const [index, value] of image[0].data.entries()) {
|
|
|
|
if (index % 4 === 3) {
|
|
|
|
// Alpha values are copied as-is
|
|
|
|
paintImage.data[index] = value;
|
|
|
|
} else {
|
|
|
|
// If dark mode is active, invert the color
|
|
|
|
paintImage.data[index] = colorMode === 'light' ? value : 255 - value;
|
|
|
|
}
|
2024-11-24 00:06:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
canvasCtx.putImageData(paintImage, 0, 0);
|
2024-11-24 18:59:11 -05:00
|
|
|
}
|
|
|
|
useEffect(paint, [colorMode, image]);
|
|
|
|
|
|
|
|
const animate = () => {
|
|
|
|
const nextImage = painter.next().value;
|
|
|
|
if (nextImage) {
|
|
|
|
setImage([nextImage])
|
|
|
|
requestAnimationFrame(animate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
useEffect(animate, [canvasCtx]);
|
2024-11-24 00:06:22 -05:00
|
|
|
|
|
|
|
return (
|
2024-11-24 18:59:11 -05:00
|
|
|
<>
|
2024-11-24 00:06:22 -05:00
|
|
|
<canvas
|
|
|
|
ref={canvasRef}
|
|
|
|
width={width}
|
|
|
|
height={height}
|
|
|
|
style={{
|
|
|
|
aspectRatio: width / height,
|
|
|
|
width: '100%'
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
{children}
|
2024-11-24 18:59:11 -05:00
|
|
|
</>
|
2024-11-24 00:06:22 -05:00
|
|
|
)
|
|
|
|
}
|