Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mouse events with d3.js and HTML5 Canvas (not SVG)

I'm fairly new to the Canvas and am completely new to d3.js...

I'm trying to use d3.js and the Canvas to create an interactive data visualisation. I have a very basic version of it working, however I'm a bit stumped on how to accurately interact with each node (a circle).

There seems to be limited info online on how to do this, or am I missing something?

I'm currently just trying to change the mouse cursor on mouseover / mouseout with the following code:

canvas.on("mousemove", function() {
   var m = d3.mouse(this);
   selectNode( m[0], m[1] );
});

var nodeI, thisNX, thisNY, nHover;

for ( i; i < nodes.length; i++ ) {

nX = nodes[i].x,
nY = nodes[i].y,
nR = nodes[i].radius - 3,
nHover = nodes[i].hover || "";

if ( mX >= nX - nR && mX <= nX + nR && mY >= nY - nR && mY <= nY + nR && nHover === "" ) {

    console.log( "mouse on!" );

    nodeI = nodes[i].index;
    thisNX = nX;
    thisNY = nY;

    $('html,body').css('cursor','pointer');

    nodes[i].hover = true;

} else {
    if ( nHover === true ) {
        console.log( "mouse off!" );
        nodes[nodeI].hover = "";
        $('html,body').css('cursor','default');
    }       
}

And here's a working fiddle: http://jsfiddle.net/u90cmm36/

I'm pretty close to getting this working, although I can't get the mouseout working correctly.

Am I going about this the correct way? It seems a little long winded to me. Where's the built in mouseover / mouseout for d3.js for the Canvas?

Thanks for your help!!

like image 227
DanV Avatar asked Sep 17 '25 04:09

DanV


1 Answers

Unfortunately, there is no built-in mouseover for canvas. There's some libraries that do it, like KineticJS, but I haven't used it much. D3, which I have used quite a bit, doesn't have built in mouseover for canvas, to my knowledge.

Usually, if I'm using d3 with canvas, I use a transparent SVG layer to control mouse interaction. This approach gives both the interactivity of SVGs and the finer graphic control of canvas, but can drag performance down if you have LOTS of interactive bits, since each different interaction requires a DOM element. You can also do things by tracking mouse position, which is what you're doing. There's a few problems with your approach, though.

Right now, you're looping through all of your nodes to check mouse position one at a time. Even if your mouse is in a node, the loop will continue and change the cursor back when it checks and sees that you aren't in the next node in the loop. You should change this to check and see if you're in ANY of the nodes, and then once you've determined if you're in a node or not, stop checking the rest of the nodes and change your cursor (if it needs to be changed.)

Your current method of checking mouseover also checks bounding squares instead of circles. This will check if the mouse is in a circle:

var distance = Math.sqrt(Math.pow(nX - mX, 2) + Math.pow(nX - mX, 2));
if(distance <= nR){ //mouseover };
like image 55
ckersch Avatar answered Sep 18 '25 18:09

ckersch