Reputation: 32217
Is there any way to leverage something like isPointInPath
when using drawImage
?
example:
drawImage
and isPointInPath
does not work.arc
and isPointInPath
works.** EDIT **
I draw a circle on one canvas, and use isPointInPath
to see if the mouse pointer is inside the circle (bottom canvas in my example).
I also "copy" the bottom canvas to the top canvas using drawImage
. Notice that isPointInPath
will not work on the top canvas (most likely due to reasons I mentioned above). Is there a work-around I can use for this that will work for ANY kind of path (or bitmap)?
Upvotes: 2
Views: 2981
Reputation: 429
I had some more challenges, because my canvas element could be rescaled. So first when I draw the figures, in my case arc, I save them in an array together with a name and draw them:
if (this.coInit == false)
{
let co = new TempCO ();
co.name= sensor.Name;
co.path = new Path2D();
co.path.arc(c.X, c.Y, this.radius, 0, 2 * Math.PI);
this.coWithPath.push(co);
}
let coWP = this.coWithPath.find(c=>c.name == sensor.Name);
this.ctx.fillStyle = color;
this.ctx.fill(coWP.path);
Then in the mouse event, I loop over the items and check if the click event is in a path. But I also need to rescale the mouse coordinates according to the resized canvas:
getCursorPosition(event) {
const rect = this.ctx.canvas.getBoundingClientRect();
const x = ((event.clientX - rect.left ) / rect.width) * this.canvasWidth;
const y = ((event.clientY - rect.top) / rect.height) * this.canvasHeight;
this.coWithPath.forEach(c=>{
if (this.ctx.isPointInPath(c.path, x, y))
{
console.log("arc is hit", c);
//Switch light
}
});
}
So I get the current size of the canvas and rescale the point to the original size. Now it works!
This is how the TempCO looks like:
export class TempCO
{
path : Path2D;
name : string;
}
Upvotes: 0
Reputation: 2367
To me, isPointInPath failed after canvas was moved. So, I used:
mouseClientX -= gCanvasElement.offsetLeft;
mouseclientY -= gCanvasElement.offsetTop;
Upvotes: 0
Reputation: 16782
You could try reimplementing ctx.drawImage()
to always draw a box behind the image itself, like so (JSFiddle example):
ctx.customDrawImage = function(image, x, y){
this.drawImage(image, x, y);
this.rect(x, y, image.width, image.height);
}
var img1 = new Image();
img1.onload = function(){
var x = y = 0;
ctx.drawImage(img1, x, y);
console.log(ctx.isPointInPath(x + 1, y + 1));
x = 1.25 * img1.width;
ctx.customDrawImage(img1, x, y);
console.log(ctx.isPointInPath(x + 1, y + 1));
Note: you might get side effects like the rectangle appearing over the image, or bleeding through from behind if you are not careful.
Upvotes: 1
Reputation: 63812
A canvas context has this hidden thing called the current path. ctx.beginPath
, ctx.lineTo
etc create this path.
When you call ctx.stroke()
or ctx.fill()
the canvas strokes or fills that path.
Even after it is stroked or filled, the path is still present in the context.
This path is the only thing that isPointInPath
tests.
If you want to test if something is in an image you have drawn or a rectangle that was drawn with ctx.fillRect()
, that is not possible using built in methods.
Typically you'd want to use a is-point-in-rectangle function that you write yourself (or get from someone else).
If you're looking for how to do pixel-perfect (instead of just the image rectangle) hit detection for an image there are various methods of doing that discussed here: Pixel perfect 2D mouse picking with Canvas
Upvotes: 4