Понимание "вызова" в D3.js с силовыми компоновками


Я новичок в D3.js, и я хочу работать с графическими макетами. У меня есть эта демонстрация, настроенная с очень простым графом, подчиняющимся силовому макету, встроенному в D3.

Http://jsfiddle.net/ewG95/

Что я хочу сделать, так это иметь возможность отключить алгоритм компоновки графа (скажем, когда пользователь нажимает пробел), а затем все еще иметь возможность перетаскивать узлы, и включить принудительную компоновку позже.

Прямо сейчас я настроил его, чтобы остановить направленную силу. расположение при попадании в пространство:

d3.select("body")
   .on("keydown", function() { 
     if (d3.event.keyCode == 32) { 
        if (forceActive) {force.stop();} else {force.resume();} 
     } 
   });

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

То есть этот фрагмент связанного кода:

var node = svg.selectAll(".node")
     .data(graph.nodes)
   .enter().append("circle")
     ...
     .call(force.drag);

Я думаю, что мне придется сделать две вещи:

  1. напишите пользовательский метод "перетаскивания", который перемещает узел и ребра, связанные с одним узлом.
  2. повторная привязка метода вызова узла к нему по мере необходимости (имеет ли это вообще смысл? Что бы заменить связанный метод? А что делает сила.драг действительно есть?).
Я хочу знать, было ли это сделано раньше, и как это сделать (вообще, возможно, не используя мою догадку о том, как это сделать).
1 2

1 ответ:

Во-первых, на ваш явный вопрос: что делает метод call()?

В d3, call - это просто функция удобства, чтобы вывернуть другие функции наизнанку. Делать

node.call( force.drag );

На самом деле то же самое, что делать

force.drag( node );
Единственное отличие состоит в том, что метод call в выборке всегда возвращает выборку, поэтому вы можете связать с ней другие методы. Итак, теперь ваш вопрос заключается в том, что делает force.drag( selection )? Он создает прослушиватели событий, которые обрабатывают мышь и касание события для поведения перетаскивания. Эти прослушиватели событий обновляют положение объекта данных узла,но они также перезапускают макет force.

Если вы не хотите, чтобы по умолчанию применялось принудительное перетаскивание макета, просто не вызывайте метод force.drag при выборе.

Поскольку вы можете настроить поведение перетаскивания так, чтобы оно не перезапускало макет force, это не похоже на то, что вы можете сделать это с force.drag (во всяком случае, без изменения исходного кода). однако, Вы можете получить доступ к большинству функций, связанных с перетаскиванием, создав свой собственный объект поведения перетаскивания и привязав его к узлам.

Затем в обработчике событий перетаскивания вы обновите позиции x и y объекта данных узла и перерисуете узел и все связанные с ним ссылки. Если ваш граф не слишком велик, вы можете сделать это, повторно вызвав функцию tick, чтобы перерисовать все элементы в соответствии с их данными; если ваш граф является большим, вы можете захотеть храните ссылки на фактические элементы в объектах данных, чтобы вы могли быстро найти правильные ссылки.

Некоторые примеры использования поведения перетаскивания (без компоновки force) Для начала работы: