【发布时间】:2016-02-01 19:39:48
【问题描述】:
我正在使用 d3 force 有向图动画。
重现问题的步骤:
- 启动 Firefox 浏览器
- 访问provemath.org
- 点击右上角的 x 或登录(此时应出现节点)
- 点击任意节点
- 点击左上角的后退箭头
结果是您单击的节点仍然附着在鼠标上,就好像您正在拖动它一样。期望的结果是这不会发生:)
见解:
这只发生在 Firefox 中。
d3相关代码:
当数据绑定到节点时,我们使用.call(gA.drag) where gA.drag = gA.force.drag(),并且在d3库本身中,我们有:
force.drag = function() {
if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend);
if (!arguments.length) return drag;
this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
};
function dragmove(d) {
d.px = d3.event.x, d.py = d3.event.y;
force.resume();
}
return d3.rebind(force, event, "on");
};
function d3_layout_forceDragstart(d) {
d.fixed |= 2;
}
function d3_layout_forceDragend(d) {
d.fixed &= ~6;
}
function d3_layout_forceMouseover(d) {
d.fixed |= 4;
d.px = d.x, d.py = d.y;
}
function d3_layout_forceMouseout(d) {
d.fixed &= ~4;
}
当数据绑定到节点时,我使用.on('mousedown', mousedown) 和.on('mouseup', mouseup)。我编写了这些函数,它们是:
function mousedown(node) {
node.time_before = getShortTime(new Date())
node.client_x_before = d3.event.clientX
node.client_y_before = d3.event.clientY
// d3.event.stopPropagation() // need cancelBubble for MS
}
function mouseup(node) {
if( mod(getShortTime(new Date()) - node.time_before, 60) < 0.85
&& cartesianDistance([node.client_x_before, node.client_y_before], [d3.event.clientX, d3.event.clientY]) < 55
) {
$.event.trigger({ type: 'node-click', message: node.id })
}
delete node.time_before
delete node.client_x_before
delete node.client_y_before
}
function getShortTime(date) {
return date.getSeconds() + date.getMilliseconds()/1000
}
function mod(m, n) {
return (m % n + n) % n;
}
我已经尝试在我的代码中的各个点同时使用d3.event.stopPropagation() 和d3.event.dataTransfer.setData('text', 'anything') 中的this 问题,但无济于事。 setData 代码似乎具有在线路运行后立即停止事件的效果,这对我来说没有意义。
一种可能但并不完全令人满意的解决方案可能是在用户单击后退箭头时手动查找并销毁拖动事件。
更新:我将包含更多代码摘录:
main.py
$(document).on('node-click', function(Event){
current_node = graph.nodes[Event.message] // graph.nodes is a DICTIONARY of nodes
updateNodeTemplateLearnedState()
blinds.open({ // in this module, new DOM elements are added with jQuery's .append() method
object: current_node,
})
hide('svg')
hide('#overlay')
show('#node-template') // This DOM element is the container that blinds.open() populated. Event WITHOUT adding new DOM elements, it is possible that the mere putting of this guy in front of the vertices is causing the issue
if( false /*mode !== 'learn'*/){
ws.jsend({ command: "re-center-graph", central_node_id: current_node.id })
}
})
function show(css_selector) { // this stuff fails for svg when using .addClass, so we can just leave show and hide stuff in the JS.
let $selected = $(css_selector)
if( !_.contains(css_show_hide_array, css_selector) ){
$selected.css('height', '100%')
$selected.css('width', '100%')
$selected.css('overflow', 'scroll')
}else{
// $selected.removeClass('hidden')
$selected.css('visibility', 'visible')
}
}
满足使用超时的建议,即使时间为“0”:
setTimeout(function() {
$.event.trigger({ type: 'node-click', message: node.id })
}, 0);
实际上是有效的,所以我认为他的理论是正确的。
【问题讨论】:
标签: javascript firefox d3.js event-handling dom-events