簡體   English   中英

當mousedown和mouseup發生在不同的元素上時,如何處理D3拖動事件?

[英]How to handle D3 drag events when mousedown and mouseup happen on different elements?

我在使用d3拖動行為時遇到問題。 之前已經回答過各種問題 ,但是我找不到針對自己特定問題的答案。

這是一個小提琴 ,它說明了我將要描述的問題。

我想要做的是在可拖動元素上具有單擊處理程序,其中不應在dragend上執行單擊處理程序。 我知道在點擊處理程序中我可以使用d3.event.defaultPrevented ,如果拖動了元素,則應將其設置為true。 mouseup事件發生在mousedown事件以外的其他元素上時,就會出現問題。 當拖動的元素的移動速度比鼠標光標慢時,就會發生這種情況。 如果釋放鼠標並且拖動的元素不在鼠標d3.event.defaultPreventedd3.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM