Alex Lenail
Alex Lenail

Reputation: 14440

d3 mousedown event fires, but mouseup event does not fire

I'm seeing some strange behavior in d3. I have a force directed graph in the usual way

node = svg.selectAll(".node").data(graph.nodes).enter().append("circle")....

and when someone clicks on a node, I want a simple animation (instead of a console.log)

function set_focus(d) { console.log('set'); }
function remove_focus() { console.log('remove'); }

node.on("mousedown", set_focus);
node.on("mouseup", remove_focus);

Interestingly, when I mousedown on a node, the set event fires, but when I release the mouse, remove_focus doesn't fire. Anyone have any idea what's going on?


d3v5, chrome 65, macOS 10.13

Upvotes: 1

Views: 2071

Answers (2)

Anne
Anne

Reputation: 131

Now you have a listener for the end of a zooming event see here

so you could do something like

d3.zoom().on('end', remove_focus)

Upvotes: 0

mattbatman
mattbatman

Reputation: 451

tldr: the zoom event is conflicting with your mouseup event.

I created a fork because I'm not too sure what you're going to want to do with this and I didn't want to mess with your git history: this link is the fork.

It seems that your Zoom event on the SVG is "consuming" all other events once the mouse is clicked. My impression is that this is a known and commonly complained about issue. I think that this GitHub ticket is related, and so is this one. Per Mike Bostock,

This is the expected behavior. Per the release notes: “The zoom behavior now consumes handled events.” So, if a mouseup event was part of a zoom gesture, then the zoom behavior stops the immediate propagation of that mouseup event preventing other listeners from receiving it (and where possible prevents the associated browser default behavior). This makes it easier to combine zooming and dragging as in this example:

http://bl.ocks.org/mbostock/3127661b6f13f9316be745e77fdfb084

If you want to prevent a zoom gesture from starting, use zoom.filter to ignore certain events, or use event.stopPropagation or event.stopImmediatePropagation to prevent the zoom behavior from receiving the initiating event. If you want to do something after a zoom gesture, listen to the zoom event.

I can get your mouseup event to fire by either deleting the d3.zoom event, or by calling d3.event.stopPropagation within the set_focus function. So, the two lines below (and in the fork) get your remove_focus function to fire, but I'm not sure if I also messed up how you want the zoom event to be working:

function set_focus(d) {
    console.log('set');
    d3.event.stopPropagation();
    node.style("opacity", function(o) { return (d == o || o.layer == d.layer - 1) ? 1 : 0.1; });
    link.style("opacity", function(o) { return (o.target == d.id) ? 1 : 0.02; });
}

function remove_focus() {
    console.log('remove');
    d3.event.stopPropagation();
    node.style("opacity", 1);
    link.style("opacity", function () { return edgeOpacity; })
}

Upvotes: 5

Related Questions