mirror of
				https://github.com/bspeice/speice.io
				synced 2025-11-03 18:10:32 -05:00 
			
		
		
		
	Use a sizing ref to avoid resizing the canvas
This commit is contained in:
		@ -2,14 +2,32 @@ import React, {useContext, useEffect, useMemo, useRef, useState} from "react";
 | 
				
			|||||||
import * as params from "../src/params";
 | 
					import * as params from "../src/params";
 | 
				
			||||||
import {PainterContext} from "../src/Canvas";
 | 
					import {PainterContext} from "../src/Canvas";
 | 
				
			||||||
import {colorFromPalette} from "./paintColor";
 | 
					import {colorFromPalette} from "./paintColor";
 | 
				
			||||||
import {chaosGameColor, ChaosGameColorProps, TransformColor} from "./chaosGameColor";
 | 
					import {chaosGameColor, Props as ChaosGameColorProps, TransformColor} from "./chaosGameColor";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import styles from "../src/css/styles.module.css";
 | 
					import styles from "../src/css/styles.module.css";
 | 
				
			||||||
import {histIndex} from "../src/camera";
 | 
					import {histIndex} from "../src/camera";
 | 
				
			||||||
import {useColorMode} from "@docusaurus/theme-common";
 | 
					import {useColorMode} from "@docusaurus/theme-common";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const paletteBarPainter = (palette: number[]) =>
 | 
					type PaletteBarProps = {
 | 
				
			||||||
    (width: number, height: number) => {
 | 
					    height: number;
 | 
				
			||||||
 | 
					    palette: number[];
 | 
				
			||||||
 | 
					    children?: React.ReactNode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const PaletteBar: React.FC<PaletteBarProps> = ({height, palette, children}) => {
 | 
				
			||||||
 | 
					    const sizingRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
 | 
					    const [width, setWidth] = useState(0);
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        if (sizingRef) {
 | 
				
			||||||
 | 
					            setWidth(sizingRef.current.offsetWidth);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }, [sizingRef]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const canvasRef = useRef<HTMLCanvasElement>(null);
 | 
				
			||||||
 | 
					    const paletteImage = useMemo(() => {
 | 
				
			||||||
 | 
					        if (width === 0) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const image = new ImageData(width, height);
 | 
					        const image = new ImageData(width, height);
 | 
				
			||||||
        for (let x = 0; x < width; x++) {
 | 
					        for (let x = 0; x < width; x++) {
 | 
				
			||||||
            const colorIndex = x / width;
 | 
					            const colorIndex = x / width;
 | 
				
			||||||
@ -23,21 +41,20 @@ const paletteBarPainter = (palette: number[]) =>
 | 
				
			|||||||
                image.data[pixelIndex + 3] = 0xff;
 | 
					                image.data[pixelIndex + 3] = 0xff;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return image;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type PaletteBarProps = {
 | 
					        return image;
 | 
				
			||||||
    height: number;
 | 
					    }, [width, height, palette]);
 | 
				
			||||||
    palette: number[];
 | 
					
 | 
				
			||||||
    children?: React.ReactNode;
 | 
					    useEffect(() => {
 | 
				
			||||||
}
 | 
					        if (canvasRef && paletteImage) {
 | 
				
			||||||
const PaletteBar: React.FC<PaletteBarProps> = ({height, palette, children}) => {
 | 
					            canvasRef.current.getContext("2d").putImageData(paletteImage, 0, 0);
 | 
				
			||||||
    const painter = useMemo(() => paletteBarPainter(palette), [palette]);
 | 
					        }
 | 
				
			||||||
 | 
					    }, [canvasRef, paletteImage]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
            <div style={{width: '100%', height, marginTop: '1em', marginBottom: '1em'}}>
 | 
					            <div ref={sizingRef} style={{width: '100%', height}}>
 | 
				
			||||||
                {/*<AutoSizingCanvas painter={painter}/>*/}
 | 
					                {width > 0 ? <canvas ref={canvasRef} width={width} height={height}/> : null}
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            {children}
 | 
					            {children}
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
@ -115,7 +132,6 @@ export default function FlameColor({quality, children}: Props) {
 | 
				
			|||||||
            height,
 | 
					            height,
 | 
				
			||||||
            transforms: params.xforms,
 | 
					            transforms: params.xforms,
 | 
				
			||||||
            final: params.xformFinal,
 | 
					            final: params.xformFinal,
 | 
				
			||||||
            quality,
 | 
					 | 
				
			||||||
            palette: params.palette,
 | 
					            palette: params.palette,
 | 
				
			||||||
            colors: [xform1Color, xform2Color, xform3Color],
 | 
					            colors: [xform1Color, xform2Color, xform3Color],
 | 
				
			||||||
            finalColor: xformFinalColor
 | 
					            finalColor: xformFinalColor
 | 
				
			||||||
 | 
				
			|||||||
@ -4,11 +4,10 @@ import {PainterContext} from "../src/Canvas";
 | 
				
			|||||||
import {chaosGameHistogram} from "./chaosGameHistogram";
 | 
					import {chaosGameHistogram} from "./chaosGameHistogram";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    quality?: number;
 | 
					    paint: (width: number, height: number, histogram: number[]) => ImageData;
 | 
				
			||||||
    paint: (width: number, histogram: Uint32Array) => ImageData;
 | 
					 | 
				
			||||||
    children?: React.ReactElement;
 | 
					    children?: React.ReactElement;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export default function FlameHistogram({quality, paint, children}: Props) {
 | 
					export default function FlameHistogram({paint, children}: Props) {
 | 
				
			||||||
    const {width, height, setPainter} = useContext(PainterContext);
 | 
					    const {width, height, setPainter} = useContext(PainterContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
@ -17,11 +16,10 @@ export default function FlameHistogram({quality, paint, children}: Props) {
 | 
				
			|||||||
            height,
 | 
					            height,
 | 
				
			||||||
            transforms,
 | 
					            transforms,
 | 
				
			||||||
            final,
 | 
					            final,
 | 
				
			||||||
            quality,
 | 
					 | 
				
			||||||
            paint
 | 
					            paint
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        setPainter(chaosGameHistogram(gameParams));
 | 
					        setPainter(chaosGameHistogram(gameParams));
 | 
				
			||||||
    }, []);
 | 
					    }, [width, height]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return children;
 | 
					    return children;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -17,7 +17,7 @@ function mixColor(color1: number, color2: number, colorSpeed: number) {
 | 
				
			|||||||
    return color1 * (1 - colorSpeed) + color2 * colorSpeed;
 | 
					    return color1 * (1 - colorSpeed) + color2 * colorSpeed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = ChaosGameFinalProps & {
 | 
					export type Props = ChaosGameFinalProps & {
 | 
				
			||||||
    palette: number[];
 | 
					    palette: number[];
 | 
				
			||||||
    colors: TransformColor[];
 | 
					    colors: TransformColor[];
 | 
				
			||||||
    finalColor: TransformColor;
 | 
					    finalColor: TransformColor;
 | 
				
			||||||
 | 
				
			|||||||
@ -14,8 +14,17 @@ type CanvasProps = {
 | 
				
			|||||||
    children?: React.ReactElement
 | 
					    children?: React.ReactElement
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export const Canvas: React.FC<CanvasProps> = ({style, children}) => {
 | 
					export const Canvas: React.FC<CanvasProps> = ({style, children}) => {
 | 
				
			||||||
    const canvasRef = useRef<HTMLCanvasElement>(null);
 | 
					    const sizingRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
 | 
					    const [width, setWidth] = useState(0);
 | 
				
			||||||
 | 
					    const [height, setHeight] = useState(0);
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        if (sizingRef.current) {
 | 
				
			||||||
 | 
					            setWidth(sizingRef.current.offsetWidth);
 | 
				
			||||||
 | 
					            setHeight(sizingRef.current.offsetHeight);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }, [sizingRef]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const canvasRef = useRef<HTMLCanvasElement>(null);
 | 
				
			||||||
    const [isVisible, setIsVisible] = useState(false);
 | 
					    const [isVisible, setIsVisible] = useState(false);
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        if (!canvasRef.current) {
 | 
					        if (!canvasRef.current) {
 | 
				
			||||||
@ -35,16 +44,7 @@ export const Canvas: React.FC<CanvasProps> = ({style, children}) => {
 | 
				
			|||||||
                observer.unobserve(canvasRef.current);
 | 
					                observer.unobserve(canvasRef.current);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }, [canvasRef]);
 | 
					    }, [canvasRef.current]);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const [width, setWidth] = useState(0);
 | 
					 | 
				
			||||||
    const [height, setHeight] = useState(0);
 | 
					 | 
				
			||||||
    useEffect(() => {
 | 
					 | 
				
			||||||
        if (canvasRef.current) {
 | 
					 | 
				
			||||||
            setWidth(canvasRef.current.offsetWidth);
 | 
					 | 
				
			||||||
            setHeight(canvasRef.current.offsetHeight);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }, [canvasRef]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [imageHolder, setImageHolder] = useState<[ImageData]>(null);
 | 
					    const [imageHolder, setImageHolder] = useState<[ImageData]>(null);
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
@ -76,25 +76,22 @@ export const Canvas: React.FC<CanvasProps> = ({style, children}) => {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }, [painter]);
 | 
					    }, [painter]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const {colorMode} = useColorMode();
 | 
					    const filter = useColorMode().colorMode === 'dark' ? 'invert(1)' : '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
            <canvas
 | 
					            <center>
 | 
				
			||||||
                ref={canvasRef}
 | 
					                <div ref={sizingRef} style={style}>
 | 
				
			||||||
                width={width}
 | 
					                    {width > 0 ? <canvas ref={canvasRef} width={width} height={height} style={{filter}}/> : null}
 | 
				
			||||||
                height={height}
 | 
					                </div>
 | 
				
			||||||
                style={{
 | 
					            </center>
 | 
				
			||||||
                    filter: colorMode === 'dark' ? 'invert(1)' : '',
 | 
					 | 
				
			||||||
                    ...style
 | 
					 | 
				
			||||||
                }}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <PainterContext.Provider value={{width, height, setPainter}}>
 | 
					            <PainterContext.Provider value={{width, height, setPainter}}>
 | 
				
			||||||
                <BrowserOnly>{() => children}</BrowserOnly>
 | 
					                {width > 0 ? children : null}
 | 
				
			||||||
            </PainterContext.Provider>
 | 
					            </PainterContext.Provider>
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const SquareCanvas: React.FC<CanvasProps> = ({style, children}) => {
 | 
					export const SquareCanvas: React.FC<CanvasProps> = ({style, children}) => {
 | 
				
			||||||
    return <Canvas style={{width: '100%', aspectRatio: '1/1', ...style}} children={children}/>
 | 
					    return <center><Canvas style={{width: '75%', aspectRatio: '1/1', ...style}} children={children}/></center>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user