Перемещение неподвижных узлов в D3


У меня есть узлы в силовом макете D3, которые установлены на .исправлено = true. Если я установлю ... x или .при значениях y сами узлы не перемещаются в новое положение.

Вот моя функция:

function fixNode(idArray, locationX, locationY) {
    for ( x = 0; x < idArray.length; x++ ) {
        for ( y = 0; y < nodes.length; y++ ) {
            if (nodes[y].id == idArray[x]) {
                nodes[y].fixed = true;
                nodes[y].x = 50;
                nodes[y].y = 50;
                break;
            }
        }
    }
}

Обновление 1:

Вот рабочая функция, основанная на совете Джейсона:

function fixNode(idArray, locationX, locationY) {
    for ( x = 0; x < idArray.length; x++ ) {
        for ( y = 0; y < nodes.length; y++ ) {
            if (nodes[y].id == idArray[x]) {
                nodes[y].fixed = true;
                nodes[y].x = 50;
                nodes[y].y = 50;
                nodes[y].px = 50;
                nodes[y].py = 50;
                break;
            }
        }
    }
    tick();
}
1 7

1 ответ:

Силонаправленная компоновка отделена от фактического рендеринга. Обычно у вас есть обработчик тиков, который обновляет атрибуты ваших SVG-элементов для каждого "тика" алгоритма компоновки (хорошая вещь в развязке-это то, что вы визуализируете <canvas> вместо этого или что-то еще).

Поэтому, чтобы ответить на ваш вопрос, вам просто нужно вызвать этот обработчик напрямую, чтобы обновить атрибуты ваших элементов SVG. Например, ваш код может выглядеть следующим образом это:

var node = …; // append circle elements

var force = d3.layout.force()
    .nodes(…)
    .links(…)
    .on("tick", tick)
    .start();

function tick() {
  // Update positions of circle elements.
  node.attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });
}
Таким образом, вы можете просто вызвать tick() в любой точке и обновить позиции элементов.

У вас может возникнуть соблазн вызвать force.tick(), но это должно использоваться в качестве синхронной альтернативы force.start(): Вы можете вызвать его повторно, и каждый вызов выполняет шаг алгоритма компоновки. Однако существует и внутренняя alpha переменная, используемая для управления моделируемым отжигом, используется внутренне, и как только макет "остынет" , эта переменная будет 0 и далее вызывается to force.tick() не будет иметь никакого эффекта. (По общему признанию, было бы неплохо, если бы force.tick() всегда запускал тиковое событие независимо от охлаждения, но это не текущее поведение).

Как вы правильно заметили в комментариях, если вы вручную устанавливаете d.x и d.y, вы также должны установить d.px и d.py с теми же значениями, если вы хотите, чтобы узел оставался в определенном положении.