Search code examples
javascriptreactjshtml5-canvas

I want to check the color at the coordinate of my click with canvas but I only get black no matter where I click


I have a react js application and I use canvas to draw squares on it. Each square has a particular color and I want when I click on it I can retrieve the color so that I can continue my program.
But no matter where I click I always get the same thing: black. While I click on for example a green square.

Here is my program to recover the color at the positioning of the click.

canvas.addEventListener("click", function (event) {
      console.log("hola")
      const x = event.clientX - canvas.offsetLeft;
      const y = event.clientY - canvas.offsetTop;
      const imageData = ctx.getImageData(x, y, 10, 10);
      console.log(imageData);
      console.log(x, y, "x/y");
      const pixelData = imageData.data;
      console.log(
        `Rouge : ${pixelData[0]}, Vert : ${pixelData[1]}, Bleu : ${pixelData[2]}, Alpha : ${pixelData[3]}`
      );

    }, false);

And this is my output with the coordonate from the click.

enter image description here

And this is an other click in other place in my canvas.

enter image description here

Like you see i have for value 0 0 0 0 instead of my color


Solution

  • In order to map the click onto the canvas (whos width and height might differ from the actual display size) you would need to first normalize the click's position and then multiply it by the height and width. First, you need a getBoundingClientRect(), as its coordinates are in the same space as clientX and clientY. Then you can use this math to get the exact pixel coordinates on the canvas the click represents:

    (client - bb.offset( / bb.size * canvas.size
    

    Then sample just a single pixel and not a 10x10 grid to get the exact clicked color.

    const canvas = document.querySelector( 'canvas' );
    const ctx = canvas.getContext( '2d' );
    
    // Create some example color we can sample
    
    const gradient = ctx.createLinearGradient( 0, 0, canvas.width, canvas.height );
    
    gradient.addColorStop( 0, 'red' );
    gradient.addColorStop( 1, 'blue' );
    
    ctx.fillStyle = gradient;
    ctx.fillRect( 0, 0, canvas.width, canvas.height );
    
    canvas.addEventListener( 'click', event => {
          
      const bb = canvas.getBoundingClientRect();
      const x = Math.floor((event.clientX - bb.left) / bb.width * canvas.width);
      const y = Math.floor((event.clientY - bb.top) / bb.height * canvas.height);
      const [ r, g, b, a ] = ctx.getImageData( x, y, 1, 1 ).data;
      const color =  `rgb(${r},${g},${b})`;
      
      console.log({ color, r, g, b, a })
      
      document.body.style.background = color;
      
    })
    <canvas width=300 height=300></canvas>