From 22a4ffff7cb4f45ae37c04a9489494e13cb5a86f Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Sun, 24 Nov 2024 00:06:22 -0500 Subject: [PATCH] Move image painting to a context component --- .../1-introduction/Canvas.tsx | 34 ----------- .../{Gasket.jsx => chaosGame.js} | 2 +- .../1-introduction/index.mdx | 4 +- .../1-introduction/scope.ts | 15 ----- .../1-introduction/scope.tsx | 30 ++++++++++ .../src/Canvas.tsx | 59 +++++++++++++++++++ 6 files changed, 92 insertions(+), 52 deletions(-) delete mode 100644 blog/2024-11-15-playing-with-fire/1-introduction/Canvas.tsx rename blog/2024-11-15-playing-with-fire/1-introduction/{Gasket.jsx => chaosGame.js} (93%) delete mode 100644 blog/2024-11-15-playing-with-fire/1-introduction/scope.ts create mode 100644 blog/2024-11-15-playing-with-fire/1-introduction/scope.tsx create mode 100644 blog/2024-11-15-playing-with-fire/src/Canvas.tsx diff --git a/blog/2024-11-15-playing-with-fire/1-introduction/Canvas.tsx b/blog/2024-11-15-playing-with-fire/1-introduction/Canvas.tsx deleted file mode 100644 index 262c50d..0000000 --- a/blog/2024-11-15-playing-with-fire/1-introduction/Canvas.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import {useEffect, useRef} from "react"; - -interface Props { - renderFn: (ImageData) => void -} - -export const Canvas: React.FC = ({renderFn}: Props) => { - const canvasRef = useRef(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 ( - - ); -}; - -export default Canvas; \ No newline at end of file diff --git a/blog/2024-11-15-playing-with-fire/1-introduction/Gasket.jsx b/blog/2024-11-15-playing-with-fire/1-introduction/chaosGame.js similarity index 93% rename from blog/2024-11-15-playing-with-fire/1-introduction/Gasket.jsx rename to blog/2024-11-15-playing-with-fire/1-introduction/chaosGame.js index 5dcc0e5..49f004f 100644 --- a/blog/2024-11-15-playing-with-fire/1-introduction/Gasket.jsx +++ b/blog/2024-11-15-playing-with-fire/1-introduction/chaosGame.js @@ -21,4 +21,4 @@ function chaosGame(image) { } } -render() +render() diff --git a/blog/2024-11-15-playing-with-fire/1-introduction/index.mdx b/blog/2024-11-15-playing-with-fire/1-introduction/index.mdx index 9e6758c..7cdeb02 100644 --- a/blog/2024-11-15-playing-with-fire/1-introduction/index.mdx +++ b/blog/2024-11-15-playing-with-fire/1-introduction/index.mdx @@ -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' -{Gasket} +{chaosGameSource}
diff --git a/blog/2024-11-15-playing-with-fire/1-introduction/scope.ts b/blog/2024-11-15-playing-with-fire/1-introduction/scope.ts deleted file mode 100644 index f020b05..0000000 --- a/blog/2024-11-15-playing-with-fire/1-introduction/scope.ts +++ /dev/null @@ -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; \ No newline at end of file diff --git a/blog/2024-11-15-playing-with-fire/1-introduction/scope.tsx b/blog/2024-11-15-playing-with-fire/1-introduction/scope.tsx new file mode 100644 index 0000000..eeefb2c --- /dev/null +++ b/blog/2024-11-15-playing-with-fire/1-introduction/scope.tsx @@ -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) => + +} +export default Scope; \ No newline at end of file diff --git a/blog/2024-11-15-playing-with-fire/src/Canvas.tsx b/blog/2024-11-15-playing-with-fire/src/Canvas.tsx new file mode 100644 index 0000000..2835555 --- /dev/null +++ b/blog/2024-11-15-playing-with-fire/src/Canvas.tsx @@ -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(null); + +interface Props { + width: number; + height: number; + children?: React.ReactNode; +} +export default function Canvas({width, height, children}) { + const [canvasCtx, setCanvasCtx] = useState(null); + const canvasRef = useCallback(node => { + if (node !== null) { + setCanvasCtx(node.getContext("2d")); + } + }, []); + + const {colorMode} = useColorMode(); + const [image, setImage] = useState(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 ( + + + {children} + + ) +} \ No newline at end of file