[英]How to handle D3 drag events when mousedown and mouseup happen on different elements?
我在使用d3拖動行為時遇到問題。 我之前已經回答過各種問題 ,但是我找不到針對自己特定問題的答案。
這是一個小提琴 ,它說明了我將要描述的問題。
我想要做的是在可拖動元素上具有單擊處理程序,其中不應在dragend
上執行單擊處理程序。 我知道在點擊處理程序中我可以使用d3.event.defaultPrevented
,如果拖動了元素,則應將其設置為true。 當mouseup
事件發生在mousedown
事件以外的其他元素上時,就會出現問題。 當拖動的元素的移動速度比鼠標光標慢時,就會發生這種情況。 如果釋放鼠標並且拖動的元素不在鼠標d3.event.defaultPrevented
則d3.event.defaultPrevented
設置為false,並且不會調用單擊處理程序。 這使得無法確定在拖動后是否觸發了click
事件。
在我的示例中,如果單擊處理程序執行但d3.event.defaultPrevented
設置為true,則圓圈閃爍綠色。 同樣,在單擊處理程序中,可以防止傳播,從而防止事件冒泡到svg單擊處理程序。 如果未執行圓圈的單擊處理程序,並且事件冒泡到svg單擊處理程序,則如果d3.event.defaultPrevented
設置為true,則圓圈將閃爍藍色,否則將閃爍紅色。
我想要實現的是使圓圈在鼠標上方的任何位置都閃爍綠色或藍色,以便能夠知道單擊事件是否在拖動之后發生。 這是否有可能,或者這是JavaScript /瀏覽器的本質限制嗎? 如果是這樣,是否有解決方法? 還是只需要在拖動圓時禁用圓的“減速”?
我在SO上發現了一個非常類似的問題 ,但實際上並沒有一個有用的答案。
任何幫助表示贊賞!
編輯看起來像是在拖動過程中阻止元素減速的想法解決了這個問題。 但是我仍然會對使用事件信息可以實現這一點感興趣。
這是小提琴的代碼:
var nodes = [{}];
var svg = d3.select('body')
.append('svg')
.attr({
width: 500,
height: 500
})
.on('click', function(){
var color = d3.event.defaultPrevented ? 'blue' : 'red';
flashNode(color);
});
var force = d3.layout.force()
.size([500, 500])
.nodes(nodes)
.friction(.2)
.on('tick', forceTickHandler);
var nodeElements = svg
.selectAll('circle');
nodeElements = nodeElements
.data(force.nodes())
.enter()
.append('circle')
.attr({
cx: 10,
cy: 10,
r: 10
})
.on('click', function(){
d3.event.stopPropagation();
var color = d3.event.defaultPrevented ? 'green' : 'orange';
flashNode(color);
})
.call(force.drag);
function forceTickHandler(e){
nodes.forEach(function(node) {
var k = e.alpha * 1.4;
node.x += (250 - node.x) * k;
node.y += (250 - node.y) * k;
});
nodeElements
.attr('cx', function(d, i){
return d.x;
})
.attr('cy', function(d, i){
return d.y;
});
};
function flashNode(color){
nodeElements
.attr('fill', color)
.transition()
.duration(1000)
.attr('fill', 'black');
}
force.start();
問題似乎來自於forceTickHandler
中更新節點位置的代碼:
nodes.forEach(function(node) {
var k = e.alpha * 1.4;
node.x += (250 - node.x) * k;
node.y += (250 - node.y) * k;
});
當注釋掉它時, node
的位置不會滯后於鼠標指針。 我不太明白上面的代碼會發生什么。 “典型”方法類似於http://bl.ocks.org/mbostock/3750558上的粘力布局示例
更新:這是一種使您接近所追求的方式: https : //jsfiddle.net/ktbe7yh4/3/
我從force.drag
創建了一個新的拖動處理程序,然后更新了dragend
發生的事情,這似乎達到了預期的效果。
代碼更改是拖動處理程序的創建:
var drag = force.drag()
.on("dragend", function(d) {
flashNode('green');
});
然后更新節點的創建以使用新的處理程序:
nodeElements = nodeElements
.data(force.nodes())
.enter()
.append('circle')
.attr({
cx: 10,
cy: 10,
r: 10
})
.on('click', function(){
d3.event.stopPropagation();
var color = d3.event.defaultPrevented ? 'green' : 'orange';
flashNode(color);
})
.call(drag);
拖動處理程序中的dragend
不管如何都會被調用,但是它仍然遇到您描述的類似問題,但是您可以在處理程序中更好地處理它。 要了解我的意思,請嘗試更改:
flashNode('green');
至:
flashNode(d3.event.defaultPrevented ? 'green' : 'orange');
並且您會看到,如果在指針直接指向圓圈時釋放鼠標,它將閃爍綠色。 如果圓圈滯后於指針,並且您在圓圈停留在光標下方之前釋放了鼠標,則它將閃爍橙色。 話雖如此,無論是否在指向圓圈的同時釋放了鼠標按鈕, dragend
處理程序中的數據元素似乎總是設置為開始拖動的圓圈。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.