Reputation: 177
I am trying to fire a mouseup event on my node for the surrounding arcs that appear upon mousedown.
My intended functionality is to be able to hold down on a node and drag it into an arc, firing the arc's as well as the node's mouseup event. I am having trouble with my current code, referenced in the JSFiddle below, and would appreciate your help!
For my arcs, I have the following code which I hope to be executed upon mouseup when letting go of the mouse above the particular arc:
slices.append('path')
...
.on('mouseup', function(arc) {
console.log(arc.data.title)
}
);
I would also hope to run the node's mouseup after having dragging the node atop the particular arc and releasing the mouse button:
svg.append("g")
.attr("class", "node")
.selectAll(".bubble")
.data(data, function(d){ return d.id; })
.enter().append("circle")
...
.on('mousedown', nodeClickedArcs)
.on('mouseup', removeArcs)
Thank you!
http://jsfiddle.net/uas6zr7y/3/
Upvotes: 3
Views: 252
Reputation: 38161
The key challenge here is that the mouse events are essentially absorbed by the circle. You could perhaps order the elements in such a manner that the a parent g
of the arcs holds a child g
with the circles to allow events to propagate up to a relevant parent, but then your circles are underneath your arcs.
One option I'll demonstrate below is to strip pointer interaction from the node during the drag. This won't interrupt the drag (tested on Chrome, Firefox, IE), but will allow the mouse to interact with other elements for mouse over / mouse out events, for example. Then we can listen for the mouse to enter (and exit) a target shape, if the drag ends (mouse up) on a target shape we can trigger a specific action.
This requires all event logic for mouse-up to be located in the drag end function, but requires listeners for mouse enter/exit for the target shape(s).
Based on the above, in the below snippet I:
In the snippet below I remove nodes (circles) if they are over a target shape (rectangles), updating the rectangles color in the process:
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 300);
var drag = d3.drag()
.on("drag",dragged)
.on("end", dragEnd);
var squares = svg.selectAll("rect")
.data([{x:30},{x:130},{x:230},{x:330},{x:430}])
.enter()
.append("rect")
.attr("x", function(d) { return d.x; })
.attr("y", 120)
.attr("width", 40)
.attr("height",40)
.attr("fill","white")
.on("mouseenter", function(d) { d.active = true; })
.on("mouseout", function(d) { d.active = false; });
var circles = svg.selectAll("circle")
.data(d3.range(20))
.enter()
.append("circle")
.attr("cx", function(d) { return d/21*500 + 25; })
.attr("cy", function(d) { return d%2 * 40 + 50; })
.attr("r", 10)
.attr("fill", function(d) { return d3.schemeCategory20[d]; })
.call(drag);
function dragged(d) {
var x = d3.mouse(this)[0];
var y = d3.mouse(this)[1];
d3.select(this)
.attr("cx",x)
.attr("cy",y)
.style("pointer-events","none");
}
function dragEnd(d) {
var rect = squares.filter(function(d) {
return d.active;
})
if(!rect.empty()) {
var circle = d3.select(this);
rect.attr("fill",interpolateColor(rect,circle));
circle.remove();
}
else {
d3.select(this).style("pointer-events","all");
}
}
function interpolateColor(r,c) {
return d3.interpolateLab(r.attr("fill"),c.attr("fill"))(0.5)
}
svg {
stroke: black;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
This checks the mouse position, not if the circle overlaps the rectangle, collision detection would require a different approach
Upvotes: 1