Макет Cytoscape Cola: Как перезапустить макет без изменения позиций?

Я пытаюсь использовать макет Cytoscape cola для рендеринга графика, который должен применять силовой макет при его использовании (поэтому при перетаскивании узлов они должны действовать так, как будто присутствует некоторая гравитация). Соответствующие библиотеки:

Моя первая проблема заключается в том, что добавление узлов к графу через add(node) не включает их в алгоритм компоновки колы. Единственный способ, который я нашел, - это уничтожить макет, повторно инициализировать его и запустить заново. Но в некоторых случаях это заставляет узлы прыгать.

Я предположил, что это произошло из-за того, что я полностью разрушил старый макет, но при настройке минимального примера я понял, что даже простой вызов layout.stop() и layout.run() приводит к перемещению узлов.

В следующем примере есть только один узел. Перемещение узла с помощью перетаскивания, затем нажатие кнопки остановки, а затем кнопки запуска заставляет узел вернуться в исходное положение:

document.addEventListener('DOMContentLoaded', function(){
        
  // Register cola layout
  cytoscapeCola(cytoscape);

  var nodes = [{ data: { id: 1, name: 1 } }]
  var edges = [];

  var cy = window.cy = cytoscape({
    container: document.getElementById('cy'),

    style: [
      {
        selector: 'node[name]',
        style: {
          'content': 'data(name)'
        }
      },

      {
        selector: 'edge',
        style: {
          'curve-style': 'bezier',
          'target-arrow-shape': 'triangle'
        }
      },
    ],

    elements: {
      nodes: nodes,
      edges: edges
    }
  });

  var layout = cy.layout({
    name: 'cola',
    infinite: true,
    fit: false,
  });
  layout.run();

  document.querySelector('#start').addEventListener('click', function() {
    layout.run();
  });

  document.querySelector('#stop').addEventListener('click', function() {
    layout.stop();
  });

  document.querySelector('#add-node').addEventListener('click', function() {
    var id = Math.random();
    cy.add({ group: 'nodes', data: { id: id, name: id } });
    cy.add({ group: 'edges', data: { source: id, target: _.head(nodes).data.id } });
    layout.stop();
    layout.destroy();
    layout = cy.layout({
      name: 'cola',
      infinite: true,
      fit: false,
    });
    layout.run();
  });

});
body {
  font-family: helvetica neue, helvetica, liberation sans, arial, sans-serif;
  font-size: 14px;
}

#cy {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  z-index: 999;
}

h1 {
  opacity: 0.5;
  font-size: 1em;
  font-weight: bold;
}

#buttons {
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 99999;
}
<!DOCTYPE>

<html>

  <head>
    <title>cytoscape-edgehandles.js demo for infinite layout</title>

    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

    <script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>

    <script src="https://unpkg.com/webcola/WebCola/cola.min.js"></script> 
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/cytoscape-cola.min.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
    <script src="cytoscape-edgehandles.js"></script>
    
    </head>

  <body>
    <h1>cytoscape-edgehandles demo with an infinite layout</h1>
    <div id="cy"></div>
    <div id="buttons">
      <button id="start">Start</button>
      <button id="stop">Stop</button>
      <button id="add-node">Add Node</button>
    </div>
  </body>

</html>

Это ошибка или я что-то не так делаю? Кто-нибудь знает, как остановить и перезапустить макет без изменения положения узлов?

Большое спасибо, Джесси


person Jesse    schedule 25.02.2021    source источник
comment
Я думаю, что график просто центрируется на вашем узле (возможно, cy.fit () и cy.center ()?)   -  person Stephan T.    schedule 26.02.2021
comment
Привет, Стефан, спасибо за идею. В этом минимальном примере может показаться, что граф просто центрирует узел. Но в примере с двумя кластерами вы увидите, что один кластер остается на месте, тогда как тот, который был перетащен перед остановкой и перезапуском макета, перескакивает после перезапуска: /   -  person Jesse    schedule 26.02.2021


Ответы (1)


Ладно, на самом деле ты был очень близок, @Stephan. Проблема заключалась в том, что WebCola по умолчанию центрирует узлы при вызове start: https://github.com/tgdwyer/WebCola/blob/78a24fc0dbf0b4eb4a12386db9c09b087633267d/src/layout.ts#L504

Оболочка cytoscape для WebCola в настоящее время не поддерживает эту опцию, поэтому я ее раздвоил и сам добавил: https://github.com/deje1011/cytoscape.js-cola/commit/f357b97aba900327e12f97b1530c4df624ff9d61

В какой-то момент я открою пул-реквест.

Теперь вы можете плавно перезапустить макет следующим образом:

layout.stop();
layout.destroy(); // cleanup event listeners
layout = graph.layout({ name: 'cola', infinite: true, fit: false, centerGraph: false });
layout.run()

Таким образом, узлы сохранят свое положение ????

person Jesse    schedule 26.02.2021