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.
And this is an other click in other place in my canvas.
Like you see i have for value 0 0 0 0 instead of my color
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>