'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.)

enter image description here

And using the floodfill algorithm, I colored as follows.

enter image description here

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