2016-10-15 4 views
1

У меня есть следующая диаграмма d3. Это всего лишь несколько узлов и связей между ними. Диаграмма делает 2 вещи:d3.behavior.zoom() прыгает вокруг

  1. Вы можете щелкнуть и перетащить отдельные узлы вокруг графика.
  2. Вы можете щелкнуть и перетащить svg для панорамирования (и увеличения с помощью колесика мыши) с помощью d3.behavior.zoom.

Моя проблема заключается в том, что если я перетаскиваю узел вокруг (например, переместите узел 20px вправо), а затем попытайтесь скопировать график, весь график сразу перепрыгнет 20px вправо (на пример). d3.behavior.zoom, по-видимому, первоначально использует d3.event для перетаскивания узла вокруг или что-то в этом роде. Не уверен. Вот код:

var data = { 
    nodes: [{ 
    name: "A", 
    x: 200, 
    y: 150, 
    size: 30 
    }, { 
    name: "B", 
    x: 140, 
    y: 300, 
    size: 15 
    }, { 
    name: "C", 
    x: 300, 
    y: 300, 
    size: 15 
    }, { 
    name: "D", 
    x: 300, 
    y: 180, 
    size: 45 
    }], 
    links: [{ 
    source: 0, 
    target: 1 
    }, { 
    source: 1, 
    target: 2 
    }, { 
    source: 2, 
    target: 3 
    }, ] 
}; 

var dragging = false; 

var svg = d3.select("body") 
    .append("svg") 
    .attr("width", "100%") 
    .attr("height", "100%") 
    .call(d3.behavior.zoom().on("zoom", function() { 
    if (dragging === false) { 
     svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")") 
    } 
    })).append("g"); 

var links = svg.selectAll("link") 
    .data(data.links) 
    .enter() 
    .append("line") 
    .attr("class", "link") 
    .attr("x1", function(l) { 
    var sourceNode = data.nodes.filter(function(d, i) { 
     return i == l.source 
    })[0]; 
    d3.select(this).attr("y1", sourceNode.y); 
    return sourceNode.x 
    }) 
    .attr("x2", function(l) { 
    var targetNode = data.nodes.filter(function(d, i) { 
     return i == l.target 
    })[0]; 
    d3.select(this).attr("y2", targetNode.y); 
    return targetNode.x 
    }) 
    .attr("fill", "none") 
    .attr("stroke", "white"); 

var nodes = svg.selectAll("node") 
    .data(data.nodes) 
    .enter() 
    .append("circle") 
    .each(function(d, i) { 
    d.object = d3.select(this); 
    console.log(d); 
    }) 
    .attr("class", "node") 
    .attr("cx", function(d) { 
    return d.x 
    }) 
    .attr("cy", function(d) { 
    return d.y 
    }) 
    .attr("r", function(d) { 
    return d.size; 
    }) 
    .on('click', function(d) { 

    }) 
    .call(d3.behavior.drag() 
    .on('dragstart', function() { 
     dragging = true; 
    }) 
    .on('dragend', function() { 
     dragging = false; 
    }) 
    .on("drag", function(d, i) { 
     d.x += d3.event.dx 
     d.y += d3.event.dy 
     d3.select(this).attr("cx", d.x).attr("cy", d.y); 
     links.each(function(l, li) { 
     if (l.source == i) { 
      d3.select(this).attr("x1", d.x).attr("y1", d.y); 
     } else if (l.target == i) { 
      d3.select(this).attr("x2", d.x).attr("y2", d.y); 
     } 
     }); 
    }) 
); 

Вот демо:

https://jsfiddle.net/25q1Lu3x/2/

Как я могу предотвратить, что сначала прыгать, пытаясь панорамирование? Я прочитал несколько вещей, которые предлагают сделать дополнительный вложенный элемент svg g и перемещать его, но это, похоже, не имеет значения.

ответ

2

Согласно D3 v3 API:

При комбинировании перетаскивать поведения с другими слушателями событий для событий взаимодействия (например, имеющие сопротивление имеет приоритет над увеличением), вы можете также рассмотреть вопрос остановки распространения на событиях-источнике предотвратить множественные действия

Итак, в вашем dragstart, просто добавьте d3.event.sourceEvent.stopPropagation();:

.on('dragstart', function() { 
    d3.event.sourceEvent.stopPropagation(); 
    dragging = true; 
}); 

Ваша любимая игра: https://jsfiddle.net/hj7krohd/