Move image painting to a context component

This commit is contained in:
Bradlee Speice 2024-11-24 00:06:22 -05:00
parent 0a45267ea1
commit 22a4ffff7c
6 changed files with 92 additions and 52 deletions

View File

@ -1,34 +0,0 @@
import {useEffect, useRef} from "react";
interface Props {
renderFn: (ImageData) => void
}
export const Canvas: React.FC<Props> = ({renderFn}: Props) => {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
useEffect(() => {
const ctx = canvasRef.current?.getContext("2d");
if (!ctx) {
console.log("Canvas not ready");
}
const image = ctx.createImageData(canvasRef.current.width, canvasRef.current.height);
renderFn(image);
ctx.putImageData(image, 0, 0);
}, []);
return (
<canvas
ref={canvasRef}
width={600}
height={600}
style={{
aspectRatio: '1 / 1',
width: '100%',
}}
/>
);
};
export default Canvas;

View File

@ -21,4 +21,4 @@ function chaosGame(image) {
}
}
render(<Canvas renderFn={chaosGame}/>)
render(<Gasket renderFn={chaosGame}/>)

View File

@ -178,9 +178,9 @@ import plotSource from '!!raw-loader!./plot'
import Playground from '@theme/Playground'
import Scope from './scope'
import Gasket from '!!raw-loader!./Gasket'
import chaosGameSource from '!!raw-loader!./chaosGame'
<Playground scope={Scope} noInline={true}>{Gasket}</Playground>
<Playground scope={Scope} noInline={true}>{chaosGameSource}</Playground>
<hr/>

View File

@ -1,15 +0,0 @@
import React from 'react';
import randomBiUnit from './biunit';
import plot from './plot';
import randomInteger from './randint';
import Canvas from './Canvas';
const Scope = {
React,
plot,
randomBiUnit,
randomInteger,
Canvas
}
export default Scope;

View File

@ -0,0 +1,30 @@
import React, {useContext, useEffect} from "react";
import randomBiUnit from './biunit';
import plot from './plot';
import randomInteger from './randint';
import Canvas, {ImageContext} from "../src/Canvas";
interface Props {
renderFn: (image: ImageData) => void;
}
function Render({renderFn}: Props) {
const {width, height, setImage} = useContext(ImageContext);
const image = new ImageData(width, height);
useEffect(() => {
renderFn(image);
setImage(image);
}, []);
return <></>;
}
const Scope = {
plot,
randomBiUnit,
randomInteger,
Canvas,
Gasket: ({renderFn}: Props) =>
<Canvas width={600} height={600}><Render renderFn={renderFn}/></Canvas>
}
export default Scope;

View File

@ -0,0 +1,59 @@
import React, {createContext, useCallback, useContext, useEffect, useRef, useState} from "react";
import {useColorMode} from "@docusaurus/theme-common";
interface IImageContext {
width: number;
height: number;
setImage: (image: ImageData) => void;
}
export const ImageContext = createContext<IImageContext>(null);
interface Props {
width: number;
height: number;
children?: React.ReactNode;
}
export default function Canvas({width, height, children}) {
const [canvasCtx, setCanvasCtx] = useState<CanvasRenderingContext2D | null>(null);
const canvasRef = useCallback(node => {
if (node !== null) {
setCanvasCtx(node.getContext("2d"));
}
}, []);
const {colorMode} = useColorMode();
const [image, setImage] = useState<ImageData>(new ImageData(width, height));
const paintImage = new ImageData(width, height);
useEffect(() => {
if (!canvasCtx) {
return;
}
for (const [index, value] of image.data.entries()) {
// If dark mode is active, invert the color scheme
const adjustValue = colorMode === 'light' ? value : 255 - value;
// Alpha values never change
paintImage.data[index] = index % 4 === 3 ? value : adjustValue;
}
console.log("Painting image");
canvasCtx.putImageData(paintImage, 0, 0);
}, [canvasCtx, colorMode, image]);
return (
<ImageContext.Provider value={{width, height, setImage}}>
<canvas
ref={canvasRef}
width={width}
height={height}
style={{
aspectRatio: width / height,
width: '100%'
}}
/>
{children}
</ImageContext.Provider>
)
}