javascript - 与 d3 中的其他元素执行双 mouseup 事件
问题描述
我正在尝试在我的节点上为 mousedown 时出现的周围弧线触发 mouseup 事件。
我的预期功能是能够按住节点并将其拖动到弧中,触发弧以及节点的 mouseup 事件。我在使用下面的 JSFiddle 中引用的当前代码时遇到问题,不胜感激!
对于我的弧线,我有以下代码,当放开特定弧线上方的鼠标时,我希望在 mouseup 时执行这些代码:
slices.append('path')
...
.on('mouseup', function(arc) {
console.log(arc.data.title)
}
);
我还希望在将节点拖动到特定弧的顶部并释放鼠标按钮后运行节点的 mouseup:
svg.append("g")
.attr("class", "node")
.selectAll(".bubble")
.data(data, function(d){ return d.id; })
.enter().append("circle")
...
.on('mousedown', nodeClickedArcs)
.on('mouseup', removeArcs)
谢谢!
解决方案
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:
- Strip pointer events from the dragged node (circles) on drag.
- Listen if the mouse moves over a target shape (rectangles) and update that element's datum to reflect its "active" status. Conversely, if the mouse moves off that target shape I set the node to be not active.
- If a drag event ends while a target shape is active, then I know that my dragged node is over the target shape (and mouse up has occurred) and can act accordingly. If the drag event ends with no active node, then I restore pointer events to the node.
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
推荐阅读
- validation - 即使在角度 6 的字段中输入值,反应形式也无效
- javascript - Javascript:如何将变量存储在构造函数中的空变量中
- linux - 在命令中用“:”替换空格
- c# - 使用 c# 编码为 CID 时从电子邮件中检索和显示内联图像
- kotlin - 从 kotlin/native 框架快速调用类
- c# - c# 创建 HTTP POST 网络请求
- javascript - npm 错误!意外的令牌 < 在 JSON 中的位置 0 解析时靠近 '
- typeorm - Typeorm 子查询添加选择
- maven - 创建汇总报告结合所有 Jtl 文件
- c# - C#:等到命令完全执行