mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
Move image painting to a context component
This commit is contained in:
parent
0a45267ea1
commit
22a4ffff7c
@ -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;
|
|
@ -21,4 +21,4 @@ function chaosGame(image) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(<Canvas renderFn={chaosGame}/>)
|
render(<Gasket renderFn={chaosGame}/>)
|
@ -178,9 +178,9 @@ import plotSource from '!!raw-loader!./plot'
|
|||||||
import Playground from '@theme/Playground'
|
import Playground from '@theme/Playground'
|
||||||
import Scope from './scope'
|
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/>
|
<hr/>
|
||||||
|
|
||||||
|
@ -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;
|
|
30
blog/2024-11-15-playing-with-fire/1-introduction/scope.tsx
Normal file
30
blog/2024-11-15-playing-with-fire/1-introduction/scope.tsx
Normal 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;
|
59
blog/2024-11-15-playing-with-fire/src/Canvas.tsx
Normal file
59
blog/2024-11-15-playing-with-fire/src/Canvas.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user