2015-08-06 4 views
0

Я пытаюсь построить граф d3 (в настоящее время только несвязанные узлы) для обработки относительно небольших значений узлов. По этой причине я использую линейную шкалу, которая динамически реагирует на входных значений и масштабирует их соответственно:d3.js Странное поведение перетаскивания при использовании динамического масштабирования

var xScale = d3.scale.linear().range([0, width]); 
var yScale = d3.scale.linear().range([height, 0]); 
[...] 
xScale.domain(d3.extent(layout, function (d){ return d.x; })); 
yScale.domain(d3.extent(layout, function (d){ return d.y; })); 

В текущей версии (вы можете найти его здесь: https://jsfiddle.net/mn1wmbe3/6/) перетягивания и значение изменение отдельных узлов работ прекрасно. Это код, я использую, чтобы переместить узел:

node.filter(function(d) { return d.selected; }) 
    .each(function(d) { 
     d.x = xScale.invert(d3.event.x); 
     d.y = yScale.invert(d3.event.y); 
    }) 
    .attr("cx", xScale(d.x)) 
    .attr("cy", yScale(d.y)); 

Как видно из других примеров, чтобы иметь возможность переместить несколько узлов одновременно я должен был бы добавить относительные координаты движения сопротивления (d3.event.dx) для каждого выбранное значение узла. Например:

node.filter(function(d) { return d.selected; }) 
    .each(function(d) { 
     d.x += xScale.invert(d3.event.dx); 
     d.y += yScale.invert(d3.event.dy); 
    }) 
    .attr("cx", xScale(d.x)) 
    .attr("cy", yScale(d.y)); 

Однако, это ведет себя не так, как ожидалось, и перемещает узлы далеко. Вы можете увидеть это в действии here.

У вас есть предложения, почему это так? Есть ли возможность обойти это и переместить несколько узлов по-другому?

ответ

0

Вам нужно всего лишь внести несколько незначительных изменений, чтобы все работало правильно. Во-первых, не изменить событие перетаскивания из:

d.x += xScale.invert(d3.event.dx); 
d.y += yScale.invert(d3.event.dy); 

To:

d.x = xScale.invert(d3.event.x); 
d.y = yScale.invert(d3.event.y); 

И все больше не будет прыгать, как раньше. Однако, если вы увеличите размер радиуса, вы заметите, что при первом перетаскивании объект будет прыгать в центр вокруг положения мыши. Это связано с тем, что теперь вам нужно указать функцию происхождения. Изменить этот код:

d3.behavior.drag() 
    .on("drag", function(d) { 

Для этого:

.call(d3.behavior.drag() 
    .origin(function(d){return {x:xScale(d.x), y:yScale(d.y)};}) 
    .on("drag", function(d) { 

с этим, при перетаскивании что-то будет помнить смещение. И теперь все будет хорошо.

Теперь, чтобы переместить многие узлы относительно, вы можете написать свой собственный dx,dy. Просто запишите координаты объекта на dragstart, а затем вычислите dx,dy на drag и добавьте эти значения в другие перемещаемые узлы.

0

Я понял. В основном, ошибка с использованием динамического масштабирования:

xScale.domain(d3.extent(layout, function (d){ return d.x; })); 
yScale.domain(d3.extent(layout, function (d){ return d.y; })); 

Из-за моих тестовых данных, это приведет к домену неоспоримым:

xScale.domain(-2, 1); 
yScale.domain(-1, 0); 

который ведет себя прекрасно, если вы Moove ваши узлы таким образом:

d.x = xScale.invert(d3.event.x); 
d.y = yScale.invert(d3.event.y); 

Однако при попытке переместить узлы путем добавления дельты расстояния (d3.event.dx) на них, то инверсию от масштаба приводит к неожиданным результатам. Причиной этого является тот факт, что xScale.invert(1) вернулся -1.994, который при добавлении к исходному значению дал неожиданные результаты.

Решение

Обходной я вычисляет расстояние между минимальным и максимальным значениями данных и устанавливает домен от нуля до этого значения:

extentX = Math.abs(d3.max(graph.layout, function(d) { return d.x;}) - d3.min(graph.layout, function(d) { return d.x;})); 
extentY = Math.abs(d3.max(graph.layout, function(d) { return d.y;}) - d3.min(graph.layout, function(d) { return d.y;})); 
xScale.domain([0, extentX]); 
yScale.domain([0, extentY]); 
Смежные вопросы