'How to extract the background color in the desired order when I click the part of the shape drawn on the canvas
In React I drew using canvas. And I got these paintings on canvas.(The numbers have been edited by me.)
And using the floodfill algorithm, I colored as follows.
I want to process the colors corresponding to the numbered areas in the image above as an array.
I want to get an array of the same shape as [Background of ①, Background of ②, Background of ③].
For example, the image below wants to be output like ['blue','yellow','red'].
If ①=yellow,②=blue,③=red, an array of ['yellow','blue','red'] will be created.
Is it possible to implement these functions via canvas? Here is my code.
import { useEffect, useRef, useState } from "react";
const allowColor = [
'{"r":255,"g":255,"b":255,"a":255}',
'{"r":255,"g":0,"b":0,"a":255}',
'{"r":255,"g":255,"b":0,"a":255}',
'{"r":0,"g":0,"b":255,"a":255}',
];
function TimeColor() {
const [nowColor, setNowColor] = useState({ r: 255, g: 255, b: 255, a: 255 });
const angles = [Math.PI * 1.5, Math.PI * 0.5, Math.PI * 0.8, Math.PI * 1.5];
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
let beginAngle = 0;
let endAngle = 0;
const ctx = canvas.getContext("2d");
for (let i = 0; i < angles.length - 1; i++) {
// Begin where we left off
beginAngle = angles[i];
// End Angle
endAngle = angles[i + 1];
// ctx.fillStyle = colors[i % colors.length];
ctx.fillStyle = "white";
ctx.beginPath();
ctx.lineWidth = 3;
// Same code as before
ctx.moveTo(200, 200);
ctx.arc(200, 200, 120, beginAngle, endAngle);
ctx.lineTo(200, 200);
ctx.stroke();
// Fill
ctx.fill();
}
}, []);
/* start flood fill functions */
const matchStartColor = function (data, pos, startColor) {
return (
data[pos] === startColor.r &&
data[pos + 1] === startColor.g &&
data[pos + 2] === startColor.b &&
data[pos + 3] === startColor.a
);
};
const colorPixel = function (data, pos, color) {
data[pos] = color.r || 0;
data[pos + 1] = color.g || 0;
data[pos + 2] = color.b || 0;
data[pos + 3] = color.hasOwnProperty("a") ? color.a : 255;
};
const floodFill = function (startX, startY, fillColor) {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
const dstImg = ctx.getImageData(0, 0, canvas.width, canvas.height);
const dstData = dstImg.data;
const startPos = (startY * canvas.width + startX) * 4;
const startColor = {
r: dstData[startPos],
g: dstData[startPos + 1],
b: dstData[startPos + 2],
a: dstData[startPos + 3],
};
if (allowColor.indexOf(JSON.stringify(startColor)) === -1) return;
if (JSON.stringify(fillColor) === JSON.stringify(startColor)) return;
const todo = [[startX, startY]];
while (todo.length) {
const pos = todo.pop();
let x = pos[0];
let y = pos[1];
let currentPos = (y * canvas.width + x) * 4;
while (y-- >= 0 && matchStartColor(dstData, currentPos, startColor)) {
currentPos -= canvas.width * 4;
}
currentPos += canvas.width * 4;
++y;
let reachLeft = false;
let reachRight = false;
while (
y++ < canvas.height - 1 &&
matchStartColor(dstData, currentPos, startColor)
) {
colorPixel(dstData, currentPos, fillColor);
if (x > 0) {
if (matchStartColor(dstData, currentPos - 4, startColor)) {
if (!reachLeft) {
todo.push([x - 1, y]);
reachLeft = true;
}
} else if (reachLeft) {
reachLeft = false;
}
}
if (x < canvas.width - 1) {
if (matchStartColor(dstData, currentPos + 4, startColor)) {
if (!reachRight) {
todo.push([x + 1, y]);
reachRight = true;
}
} else if (reachRight) {
reachRight = false;
}
}
currentPos += canvas.width * 4;
}
}
ctx.putImageData(dstImg, 0, 0);
};
/* end flood fill funtions */
const changeColor = (e) => {
floodFill(e.clientX, e.clientY, nowColor);
};
return (
<>
<canvas ref={canvasRef} width={400} height={400} onClick={changeColor} />
<div
style={{ display: "flex", justifyContent: "space-around", width: 400 }}
>
<div
style={{
background: "red",
width: 50,
height: 50,
borderRadius: 10,
cursor: "pointer",
}}
onClick={() => setNowColor({ r: 255, g: 0, b: 0, a: 255 })}
/>
<div
style={{
background: "blue",
width: 50,
height: 50,
borderRadius: 10,
cursor: "pointer",
}}
onClick={() => setNowColor({ r: 0, g: 0, b: 255, a: 255 })}
/>
<div
style={{
background: "yellow",
width: 50,
height: 50,
borderRadius: 10,
cursor: "pointer",
}}
onClick={() => setNowColor({ r: 255, g: 255, b: 0, a: 255 })}
/>
</div>
</>
);
}
export default TimeColor;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|


