Я хочу разрешить пользователям просматривать свою сеть с помощью d3 forceSimulation или макет CoLa, что означает, что когда пользователь запускает событие, мне нужно чтобы изменить, какой из этих алгоритмов компоновки обновляет атрибуты x и y моих узлов и ребер.

В частности, это требует, чтобы я мог останавливать моделирование и не позволять им обновлять эти атрибуты данных, которые я им даю, пока другой является «активным», а также удалять связанные с ними обработчики перетаскивания.

Моя функция рендеринга в настоящее время имеет:

    if (use_cola) {

        // MUST TURN OFF D3 AND ITS DRAG HANDLERS!

        force = cola_force.nodes(graph.nodes)
                          .links(links)
                          .groups(groups[group_nodes_by])
                          .jaccardLinkLengths(repulsion_strength, 0.7)
                          .avoidOverlaps(true)
                          .start(50, 0, 50);

        node.call(cola_force.drag);
        group.call(cola_force.drag);

        cola_force.on('tick',  ticked);

    } else {  // d3

        // MUST TURN OFF COLA AND ITS DRAG HANDLERS!

        force = d3_force.nodes(graph.nodes)
                        .force("link", d3.forceLink(links))
                        .force("charge", d3.forceManyBody().strength(-repulsion_strength))
                        .force("center", d3.forceCenter(w/2,h/2));

        node.call(d3.drag()
             .on("start", dragstarted)
             .on("drag", dragged)
             .on("end", dragended));  // where those are the conventional functions

        d3_force.on('tick', ticked);
    } 

Одним из решений может быть искажение этих объектов, например delete d3_force['something_important']

Что-нибудь попроще может сработать, например d3_force.nodes([]) или что-то в этом роде.

Я не уверен, как бы я сделал что-то подобное с обработчиками перетаскивания, потому что я менее знаком с их работой.

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

Частичное решение, предлагаемое для обработчика перетаскивания d3 (в d3v3) здесь :

var dragCallback = d3.select('rect#no-drag').property('__onmousedown.drag')['_'];

d3.select('rect#no-drag').on('mousedown.drag', null);

А затем восстановить его позже:

d3.selectAll('rect#no-drag').on('mousedown.drag', dragCallback);
2
Alex Lenail 21 Ноя 2018 в 06:00

1 ответ

Лучший ответ

Вам нужно сделать две вещи:

  1. Остановите симуляцию, если она все еще запущена, чтобы она не испортила координаты ваших узлов. Это легко сделать, позвонив по телефону d3_force.stop(). Однако нет необходимости сначала проверять, работает ли он, потому что вызов его в уже остановленной симуляции тоже не повредит.

    Позже вы можете повторно активировать симуляцию, просто позвонив d3_force.restart(), возможно, перекачивая немного энергии, чтобы нагреть его: d3_force.alpha(1).restart().

  2. В документации рассказывается, как избавиться от поведения перетаскивания:

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

      selection.on (". drag", null);   

    В вашем случае это будет node.on(".drag", null). Если пользователь переключает макет обратно, вы можете снова связать поведение перетаскивания с выбором node. Для этого, возможно, стоит подумать о том, чтобы заранее создать поведение перетаскивания и просто передать ссылку при повторном связывании позже.

4
altocumulus 7 Дек 2018 в 10:18