Почему d3.js v3 разбивает мой график силы при реализации масштабирования, когда v2 не работает?

У меня есть силовая компоновка, которую я создал с помощью d3.js

Я хотел бы иметь как нормальную функциональность перетаскиваемого силового макета, так и возможность масштабирования.

Я в основном копировал/вставлял код масштабирования из этого (http://jsfiddle.net/nrabinowitz/QMKm3/) кода. Это тот же способ масштабирования, который использует Майк Босток в этом (http://bl.ocks.org/mbostock/3680957).

Вот мой код: http://jsfiddle.net/kM4Hs/6/

Как видно на мой взгляд, масштабирование работает отлично, но я не могу выбрать отдельные узлы в макете силы и перетащить их.

Я считаю, что причиной этого является тот факт, что оба других автора используют d3.v2.js, а не новый d3.v3.js, который я использую. Когда я меняю свой импорт на v2, он отлично работает. Однако, в интересах прогресса и просто всеобщей доброжелательности, я хотел бы использовать v3, если это возможно.

<script type='text/javascript' src='http://d3js.org/d3.v3.min.js'></script>

                    versus

<script type='text/javascript' src='http://d3js.org/d3.v2.min.js'></script>

Два вопроса: почему v3 нарушает компоновку сил, когда v2 не делает, и, что более важно, что я могу сделать, если что-нибудь, исправить?

Спасибо заранее!

Ответ 1

Если вы читаете примечания к выпуску, вы увидите полное объяснение всего, что изменилось между окончательной версией 2.x(2.10.3) и последним релиз, 3.2.7. В частности, из версии 3.2.2:

Лучшая обработка жестов перетаскивания в d3.behavior.drag, d3.behavior.zoom и d3.svg.brush, не предотвращая поведения по умолчанию или не останавливая распространение. Например, mousedown теперь меняет фокус, mouseup вне iframe работает правильно, а touchstart не заикается.

Итак, в V2 поведение перетаскивания может иметь приоритет над поведением масштабирования, останавливая распространение при событиях масштабирования. В V3 это больше не происходит автоматически, что дает вам выбор того, какое поведение имеет приоритет, и когда.

Если вы хотите присвоить приоритет поведения перетаскивания при перетаскивании узлов, тогда вам нужно stopPropagation при вводе событий при перетаскивании, чтобы что эти события не интерпретируются одновременно как панорамирование по изменению масштаба. Остановить распространение на dragstart достаточно:

var drag = d3.behavior.drag()
    .on("dragstart", function() { d3.event.sourceEvent.stopPropagation(); })
    .on("drag", function() { /* handle drag event here */ });

При использовании компоновки синтаксиса код:

var drag = force.drag()
    .on("dragstart", function() { d3.event.sourceEvent.stopPropagation(); });

Рабочий пример:

drag and zoom

Примечание. Объединение этих двух типов поведения означает, что интерпретация жестов неоднозначна и очень чувствительна к положению. Щелчок по кругу интерпретируется как перетаскивание этого круга, тогда как щелчок на один пиксель может быть интерпретирован как панорамирование фона. Более надежный метод объединения этих поведений заключается в использовании модальности. Например, если пользователь удерживает клавишу SPACE, нажатие и перетаскивание интерпретируется как панорамирование, а не перетаскивание, независимо от местоположения клика. Этот подход обычно используется в коммерческом программном обеспечении, таком как Adobe Photoshop.