diff --git a/src/index.tsx b/src/index.tsx index 7cebdb8..b364f57 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -10,13 +10,48 @@ export type ColorWheelProps = Omit, 'color'> & { color?: {hue: number, saturation: number, value: number}; defaultColor?: {hue: number, saturation: number, value: number}; onChange?: (colors: { hue: number; saturation: number; value: number }[]) => void; + value?: number } -export const ColorWheel = ({ radius, harmony: harmonyName, color, defaultColor, onChange, ...props }: ColorWheelProps) => { +export const ColorWheel = ({ radius, harmony: harmonyName, color, defaultColor, onChange, value = 1.0, ...props }: ColorWheelProps) => { const ref = useRef(null); - const [position, setPosition] = useState(defaultColor ? hsv2xy(defaultColor.hue, defaultColor.saturation, defaultColor.value, radius) : hsv2xy(0, 1, 1, radius)); + const [position, setPosition] = useState(defaultColor ? hsv2xy(defaultColor.hue, defaultColor.saturation, defaultColor.value, radius) : hsv2xy(0, 1, value, radius)); const harmony = useMemo(() => harmonies[harmonyName], [harmonies, harmonyName]); + const drawCircle = useCallback((ctx: CanvasRenderingContext2D) => { + let image = ctx.createImageData(2 * radius, 2 * radius); + let data = image.data; + + for (let x = -radius; x < radius; x++) { + for (let y = -radius; y < radius; y++) { + let [r, phi] = xy2polar(x, y); + + let deg = rad2deg(phi); + + // Figure out the starting index of this pixel in the image data array. + let rowLength = 2 * radius; + let adjustedX = x + radius; // convert x from [-50, 50] to [0, 100] (the coordinates of the image data array) + let adjustedY = y + radius; // convert y from [-50, 50] to [0, 100] (the coordinates of the image data array) + let pixelWidth = 4; // each pixel requires 4 slots in the data array + let index = (adjustedX + adjustedY * rowLength) * pixelWidth; + + let hue = deg; + let saturation = r / radius; + + let [red, green, blue] = hsv2rgb(hue, saturation, value); + let alpha = 255; + + data[index] = red; + data[index + 1] = green; + data[index + 2] = blue; + data[index + 3] = alpha; + } + } + + ctx.putImageData(image, 0, 0); + }, [radius, value]); + + useEffect(() => { if (!ref.current) return; const ctx = ref.current.getContext('2d'); @@ -27,7 +62,7 @@ export const ColorWheel = ({ radius, harmony: harmonyName, color, defaultColor, ctx.canvas.height = radius * 2 drawCircle(ctx); - }, []); + }, [drawCircle]); useEffect(() => { if (color) { @@ -56,7 +91,6 @@ export const ColorWheel = ({ radius, harmony: harmonyName, color, defaultColor, const hue = rad2deg(phi); const saturation = r / radius; - const value = 1.0; const colors = harmony.map(harmonyHue => { let newHue = (hue + harmonyHue) % 360; @@ -69,44 +103,9 @@ export const ColorWheel = ({ radius, harmony: harmonyName, color, defaultColor, onChange?.([{ hue, saturation, value }, ...colors]); return colors; - }, [position, harmony, polar2xy, onChange, xy2polar, rad2deg, radius]); - - - const drawCircle = useCallback((ctx: CanvasRenderingContext2D) => { - let image = ctx.createImageData(2 * radius, 2 * radius); - let data = image.data; - - for (let x = -radius; x < radius; x++) { - for (let y = -radius; y < radius; y++) { - let [r, phi] = xy2polar(x, y); - - let deg = rad2deg(phi); - - // Figure out the starting index of this pixel in the image data array. - let rowLength = 2 * radius; - let adjustedX = x + radius; // convert x from [-50, 50] to [0, 100] (the coordinates of the image data array) - let adjustedY = y + radius; // convert y from [-50, 50] to [0, 100] (the coordinates of the image data array) - let pixelWidth = 4; // each pixel requires 4 slots in the data array - let index = (adjustedX + adjustedY * rowLength) * pixelWidth; - - let hue = deg; - let saturation = r / radius; - let value = 1.0; - - let [red, green, blue] = hsv2rgb(hue, saturation, value); - let alpha = 255; - - data[index] = red; - data[index + 1] = green; - data[index + 2] = blue; - data[index + 3] = alpha; - } - } - - ctx.putImageData(image, 0, 0); - }, [radius]); + }, [position, harmony, polar2xy, onChange, xy2polar, rad2deg, radius, value]); - const [r, g, b] = useMemo(() => xy2rgb(position.x, position.y, radius), [position, radius]); + const [r, g, b] = useMemo(() => xy2rgb(position.x, position.y, radius, value), [position, radius, value]); return (
{ +export const xy2rgb = (x: number, y: number, radius: number, value: number = 1.0) => { x -= radius; y -= radius; @@ -66,7 +66,6 @@ export const xy2rgb = (x: number, y: number, radius: number) => { const hue = rad2deg(phi); const saturation = r / radius; - const value = 1.0; return hsv2rgb(hue, saturation, value); }