I have an HTML canvas with all different shapes of all different sizes and it is built by parsing information from an external file. I am wondering how I can make it so that hovering the mouse over each shape will display its unique name. I have found resources on how to display text on a mouse hover for the whole canvas, but I need each individual shape to display a unique text. Thanks!
-
Here's an option: http://stackoverflow.com/a/1221514/4533609 – Scheda Jun 11 '15 at 19:47
-
Here is a possible option as well with support for isPointInPath and pixel detection of text letters: http://stackoverflow.com/questions/18935737/text-collision-detection/18935984#18935984 – Jun 11 '15 at 20:48
2 Answers
You can use context.isPointInPath to test if your mouse is hovering over one of your shapes.
Create a javascript object representing each shape from the external file.
var triangle={ name:'triangle', color:'skyblue', points:[{x:100,y:100},{x:150,y:150},{x:50,y:150}] };Create a function that takes a shape-object and makes a Path from that shape-object:
function defineShape(s){ ctx.beginPath(); ctx.moveTo(s[0].x,s[0].y); for(var i=1;i<s.length;i++){ ctx.lineTo(s[i].x,s[i].y); } ctx.closePath(); }Use
context.isPointInPathto test if the mouse is inside the most recently defined path (from step#2).// define the path to be tested defineShape(triangle); // test if the mouse is inside that shape if(context.isPointInPath(mouseX,mouseY){ // the mouse is inside the shape }
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
ctx.font='14px verdana';
var shapes=[];
var triangle1={
name:'triangle1',
color:'skyblue',
drawcolor:'skyblue',
points:[{x:100,y:100},{x:150,y:150},{x:50,y:150}]
};
var triangle2={
name:'triangle2',
color:'palegreen',
drawcolor:'palegreen',
points:[{x:220,y:100},{x:270,y:150},{x:170,y:150}]
};
shapes.push(triangle1,triangle2);
$("#canvas").mousemove(function(e){handleMouseMove(e);});
drawAll();
function drawAll(){
for(var i=0;i<shapes.length;i++){
var s=shapes[i];
defineShape(s.points);
ctx.fillStyle=s.drawcolor;
ctx.fill();
ctx.stroke();
if(s.color!==s.drawcolor){
ctx.fillStyle='black';
ctx.fillText(s.name,s.points[0].x,s.points[0].y);
}
}
}
function defineShape(s){
ctx.beginPath();
ctx.moveTo(s[0].x,s[0].y);
for(var i=1;i<s.length;i++){
ctx.lineTo(s[i].x,s[i].y);
}
ctx.closePath();
}
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// clear the canvas
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<shapes.length;i++){
var s=shapes[i];
// define the shape path we want to test against the mouse position
defineShape(s.points);
// is the mouse insied the defined shape?
if(ctx.isPointInPath(mouseX,mouseY)){
// if yes, fill the shape in red
s.drawcolor='red';
}else{
// if no, fill the shape with blue
s.drawcolor=s.color;
}
}
drawAll();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Hover the mouse over the shape.</h4>
<canvas id="canvas" width=300 height=300></canvas>
- 102,905
- 11
- 164
- 176
Are you willing to use a library, or are you attached to a purely native canvas implementation? With purely native canvas, this could get quite annoying, because you would have to not only get the mouse coordinates of the pointer, but also keep track of the position of every object and check whether or not the mouse is at that position every time the mouse moves. I coded that functionality once, and it was annoying enough with just a few rectangles to keep track of.
On the other hand, if you use KineticJS to do your canvas drawing (or presumably others; KineticJS is just the one I've used), all that annoyance is handled for you. The objects you create and add to the canvas can have event handlers attached to them using the KineticJS library, and it will be only minimally harder than reacting to mouseover events on any other HTML element. This link shows how to do it.
http://www.html5canvastutorials.com/kineticjs/html5-canvas-listen-or-dont-listen-to-events-with-kineticjs/
- 557
- 5
- 13