使用 cytoscape.js 展开和折叠组时如何保持先前的位置

How to keep the previous position when expand and collapse group with cytoscape.js

我一直在寻找一个好的拓扑布局 javascript 库。学习了很多库D3, WebCola,等等,最终被深深吸引 cytoscape and its amazing extension cytoscape.js-expand-collapse

我要的是一个javascript布局库,节点多可以合理布局。父节点包含子节点,即节点之间存在继承关系。

This Demo 几乎正是我所需要的。展开和折叠功能真的很棒。

然后我在上面的演示的基础上创建了我的演示。但是,当展开节点然后折叠节点时,图形上的所有节点都会发生变化。

初始图

节点第一次展开收起后的状态

节点第二次展开收起后的状态

显然这不是我的需要。而我又重新学习了原来的官方demo。我发现演示的 elements 值在每个数据上都有 position

{"data":{"id":"nwtN_50c55b8c-3489-4c4e-8bea-6a1c1162ac9c"},"position":{"x":577.5410894097904,"y":612.5647477282114},"group":"nodes"}

我知道如果每个数据都有合理的坐标,展开和折叠一些节点后所有节点的位置都不会改变。

关键是我不知道坐标,我无法为我的节点设置初始坐标。我觉得布局的核心算法就是为每个点计算出合适的坐标点。

所以,我无法为所有节点设置初始坐标,我希望所有节点的位置都是固定的,无论展开和折叠任何节点。可能吗?

下面是我的demo

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

    ready: function() {
      var api = this.expandCollapse({
        layoutBy: {
          name: "cose-bilkent",
          animate: "end",
          randomize: false,
          fit: false
        },
        fisheye: true,
        animate: false,
        undoable: false
      });
      api.collapseAll();
    },

    style: [{
      selector: 'node',
      style: {
        'label': 'data(id)'
      }
    }],

    elements: [{
      "group": "nodes",
      "data": {
        "id": "n_0",
        "name": "External Network"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "n_4",
        "name": "虚拟机网络",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "n_3",
        "name": "VM Network 2",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_128",
        "name": "bfcui-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_105",
        "name": "bychen-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_93",
        "name": "CE-bj",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_100",
        "name": "changliu-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_67",
        "name": "chaoma-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_83",
        "name": "chenwang",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_68",
        "name": "cwang-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_15",
        "name": "gqpei-bj",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_1",
        "name": "gwxu-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_118",
        "name": "gyzhao-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_76",
        "name": "hlli-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_18",
        "name": "hwzhang-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_40",
        "name": "hxqu-pc"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_69",
        "name": "hxwang-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_71",
        "name": "jbshi-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_64",
        "name": "jdai-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_16",
        "name": "jfxiao-bj",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_78",
        "name": "jhhou-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_91",
        "name": "jjsun-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_17",
        "name": "jppan-bj",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_45",
        "name": "jqwang-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_50",
        "name": "jxli-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_42",
        "name": "jyyou-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_28",
        "name": "jyzhou-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_46",
        "name": "jzhao-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_19",
        "name": "lfeng-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_65",
        "name": "lhzhen-pc",
        "parent": "group2"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_1",
        "source": "n_0",
        "target": "v_1"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_100",
        "source": "n_0",
        "target": "v_100"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_46",
        "source": "n_0",
        "target": "v_46"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_64",
        "source": "n_0",
        "target": "v_64"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_65",
        "source": "n_0",
        "target": "v_65"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_67",
        "source": "n_0",
        "target": "v_67"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_69",
        "source": "n_0",
        "target": "v_69"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_71",
        "source": "n_0",
        "target": "v_71"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_76",
        "source": "n_0",
        "target": "v_76"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_78",
        "source": "n_0",
        "target": "v_78"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_83",
        "source": "n_0",
        "target": "v_83"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_91",
        "source": "n_0",
        "target": "v_91"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_1n_0",
        "source": "v_1",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_1v_128",
        "source": "v_1",
        "target": "v_128"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_100n_0",
        "source": "v_100",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_16",
        "source": "v_118",
        "target": "v_16"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_18",
        "source": "v_118",
        "target": "v_18"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_46",
        "source": "v_118",
        "target": "v_46"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_67",
        "source": "v_118",
        "target": "v_67"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_69",
        "source": "v_118",
        "target": "v_69"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_71",
        "source": "v_118",
        "target": "v_71"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_78",
        "source": "v_118",
        "target": "v_78"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128n_0",
        "source": "v_128",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128v_1",
        "source": "v_128",
        "target": "v_1"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128v_105",
        "source": "v_128",
        "target": "v_105"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128v_46",
        "source": "v_128",
        "target": "v_46"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128v_65",
        "source": "v_128",
        "target": "v_65"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_15n_0",
        "source": "v_15",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_50v_40",
        "source": "v_50",
        "target": "v_40"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_50v_46",
        "source": "v_50",
        "target": "v_46"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_50v_64",
        "source": "v_50",
        "target": "v_64"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_65v_19",
        "source": "v_65",
        "target": "v_19"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_65v_91",
        "source": "v_65",
        "target": "v_91"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_67n_0",
        "source": "v_67",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_67v_100",
        "source": "v_67",
        "target": "v_100"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_67v_105",
        "source": "v_67",
        "target": "v_105"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_67v_42",
        "source": "v_67",
        "target": "v_42"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_91v_16",
        "source": "v_91",
        "target": "v_16"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_91v_18",
        "source": "v_91",
        "target": "v_18"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_91v_28",
        "source": "v_91",
        "target": "v_28"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_91v_45",
        "source": "v_91",
        "target": "v_45"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "group2"
      }
    }]
  });
  var api = cy.expandCollapse('get');
  var beforeExpand = null;
cy.unbind('expandcollapse.beforeexpand');
cy.nodes().bind('expandcollapse.beforeexpand', function(event) { 
   if (beforeExpand == null) 
      beforeExpand = cy.elements().clone();  // save the graph before the first expand
}); // Triggered before a node is expanded

cy.unbind('expandcollapse.aftercollapse');
cy.nodes().bind('expandcollapse.aftercollapse', function(event) { 
   if(beforeExpand != null) {
       cy.elements().remove();
       cy.add(beforeExpand);  // set the graph to original values
       beforeExpand = null;
   }
}); 
});
body {
  font-family: helvetica neue, helvetica, liberation sans, arial, sans-serif;
  font-size: 14px;
}

#cy {
  z-index: 999;
  width: 100%;
  height: 100%;
}

h1 {
  opacity: 0.5;
  font-size: 1em;
  font-weight: bold;
}
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="https://unpkg.com/cytoscape@3.1.0/dist/cytoscape.min.js"></script>

<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/cytoscape-cose-bilkent@4.0.0/cytoscape-cose-bilkent.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse@3.1.1/cytoscape-expand-collapse.js"></script>
<div id="cy"></div>

最后总结一下我需要的:

  1. 带有一些节点的初始化图,可以根据 属性 类型进行扩展。 type=1 的节点是可扩展的,type=2 的节点不是。

  2. 所有节点做合理布局,如layoutBy:{name:'cose-bilkent'}

  3. 展开一个节点(如:A)时,发送ajax请求获取子节点(如:A1、A2、A3),​​然后布局子节点。该图可能需要适当的调整。我希望是增量布局,而不是完全重新布局。

  4. 折叠之前的复合节点(A组A1,A2,A3)时,图上的所有节点都保持之前的位置。

  5. 展开最后一个组节点(如:A)时,子节点也保持原来的位置

我觉得我的要求很基本,但是我找不到展示这个功能的演示?我是否清楚地描述了我的要求?

有人可以帮助我吗?提前致谢。非常感谢。

您尝试做的事情效率不高。你自己说过,你不知道节点的坐标,所以 cytoscape 也不知道。但尽管如此,cose-blikent 仍然尽可能好地定位元素。位置可能会改变,但结构保持不变。确实没有任何问题可以证明您必须经历的麻烦和工作。

如果你真的想实现这个,我想你可以在已经发生的特定事件中做到这一点:

代码:

var nodes = cy.nodes();
var positions = [];
for (node in nodes) {
    positions[node] = nodes[node].position(); // save the i'th nodes positions
}

然后折叠父级并再次展开后,您可以设置之前存储的所有节点位置:

var nodes = cy.nodes();
for (node in nodes) {
    nodes[node].position(positions[node]); // set x and y of node
}

事件:

cy.nodes().on("expandcollapse.beforecollapse", function(event) { var node = this; ... }) // Triggered before a node is collapsed

cy.nodes().on("expandcollapse.aftercollapse", function(event) { var node = this; ... }) // Triggered after a node is collapsed

cy.nodes().on("expandcollapse.beforeexpand", function(event) { var node = this; ... }) // Triggered before a node is expanded

cy.nodes().on("expandcollapse.afterexpand", function(event) { var node = this; ... }) // Triggered after a node is expanded

编辑:

var beforeExpand = null;
cy.unbind('expandcollapse.beforeexpand');
cy.nodes().bind('expandcollapse.beforeexpand', function(event) { 
   if (beforeExpand == null) 
      beforeExpand = cy.elements().clone();  // save the graph before the first expand
}); // Triggered before a node is expanded

cy.unbind('expandcollapse.aftercollapse');
cy.nodes().bind('expandcollapse.aftercollapse', function(event) { 
   if(beforeExpand != null) {
       cy.elements().remove();
       cy.add(beforeExpand);  // set the graph to original values
       beforeExpand = null;
   }
}); // Triggered before a node is expanded

编辑:

修复演示的方法如下:

  • 将 fit: false 更改为 fit: true
  • 改变你的css cytoscape 就像下面的片段

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

    ready: function() {
      var api = this.expandCollapse({
        layoutBy: {
          name: "cose-bilkent",
          animate: "end",
          randomize: false,
          fit: true               // set this to true
        },
        fisheye: true,
        animate: false,
        undoable: false
      });
      api.collapseAll();
    },

    style: [{
      selector: 'node',
      style: {
        'label': 'data(id)'
      }
    }],

    elements: [{
      "group": "nodes",
      "data": {
        "id": "n_0",
        "name": "External Network"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "n_4",
        "name": "虚拟机网络",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "n_3",
        "name": "VM Network 2",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_128",
        "name": "bfcui-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_105",
        "name": "bychen-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_93",
        "name": "CE-bj",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_100",
        "name": "changliu-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_67",
        "name": "chaoma-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_83",
        "name": "chenwang",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_68",
        "name": "cwang-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_15",
        "name": "gqpei-bj",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_1",
        "name": "gwxu-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_118",
        "name": "gyzhao-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_76",
        "name": "hlli-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_18",
        "name": "hwzhang-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_40",
        "name": "hxqu-pc"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_69",
        "name": "hxwang-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_71",
        "name": "jbshi-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_64",
        "name": "jdai-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_16",
        "name": "jfxiao-bj",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_78",
        "name": "jhhou-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_91",
        "name": "jjsun-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_17",
        "name": "jppan-bj",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_45",
        "name": "jqwang-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_50",
        "name": "jxli-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_42",
        "name": "jyyou-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_28",
        "name": "jyzhou-pc",
        "parent": "group2"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_46",
        "name": "jzhao-pc",
        "parent": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_19",
        "name": "lfeng-pc",
        "parent": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "v_65",
        "name": "lhzhen-pc",
        "parent": "group2"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_1",
        "source": "n_0",
        "target": "v_1"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_100",
        "source": "n_0",
        "target": "v_100"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_46",
        "source": "n_0",
        "target": "v_46"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_64",
        "source": "n_0",
        "target": "v_64"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_65",
        "source": "n_0",
        "target": "v_65"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_67",
        "source": "n_0",
        "target": "v_67"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_69",
        "source": "n_0",
        "target": "v_69"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_71",
        "source": "n_0",
        "target": "v_71"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_76",
        "source": "n_0",
        "target": "v_76"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_78",
        "source": "n_0",
        "target": "v_78"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_83",
        "source": "n_0",
        "target": "v_83"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "n_0v_91",
        "source": "n_0",
        "target": "v_91"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_1n_0",
        "source": "v_1",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_1v_128",
        "source": "v_1",
        "target": "v_128"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_100n_0",
        "source": "v_100",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_16",
        "source": "v_118",
        "target": "v_16"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_18",
        "source": "v_118",
        "target": "v_18"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_46",
        "source": "v_118",
        "target": "v_46"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_67",
        "source": "v_118",
        "target": "v_67"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_69",
        "source": "v_118",
        "target": "v_69"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_71",
        "source": "v_118",
        "target": "v_71"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_118v_78",
        "source": "v_118",
        "target": "v_78"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128n_0",
        "source": "v_128",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128v_1",
        "source": "v_128",
        "target": "v_1"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128v_105",
        "source": "v_128",
        "target": "v_105"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128v_46",
        "source": "v_128",
        "target": "v_46"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_128v_65",
        "source": "v_128",
        "target": "v_65"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_15n_0",
        "source": "v_15",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_50v_40",
        "source": "v_50",
        "target": "v_40"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_50v_46",
        "source": "v_50",
        "target": "v_46"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_50v_64",
        "source": "v_50",
        "target": "v_64"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_65v_19",
        "source": "v_65",
        "target": "v_19"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_65v_91",
        "source": "v_65",
        "target": "v_91"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_67n_0",
        "source": "v_67",
        "target": "n_0"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_67v_100",
        "source": "v_67",
        "target": "v_100"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_67v_105",
        "source": "v_67",
        "target": "v_105"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_67v_42",
        "source": "v_67",
        "target": "v_42"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_91v_16",
        "source": "v_91",
        "target": "v_16"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_91v_18",
        "source": "v_91",
        "target": "v_18"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_91v_28",
        "source": "v_91",
        "target": "v_28"
      }
    }, {
      "data": {
        "group": "edges",
        "id": "v_91v_45",
        "source": "v_91",
        "target": "v_45"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "group0"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "group1"
      }
    }, {
      "group": "nodes",
      "data": {
        "id": "group2"
      }
    }]
  });
  var api = cy.expandCollapse('get');
  var beforeExpand = null;
cy.unbind('expandcollapse.beforeexpand');
cy.nodes().bind('expandcollapse.beforeexpand', function(event) { 
   if (beforeExpand == null) 
      beforeExpand = cy.elements().clone();  // save the graph before the first expand
}); // Triggered before a node is expanded

cy.unbind('expandcollapse.aftercollapse');
cy.nodes().bind('expandcollapse.aftercollapse', function(event) { 
   if(beforeExpand != null) {
       cy.elements().remove();
       cy.add(beforeExpand);  // set the graph to original values
       beforeExpand = null;
   }
}); 
});
body {
  font-family: helvetica;
  font-size: 14px;
}
#cy { /*change your css*/
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 999;
}
h1 {
  opacity: 0.5;
  font-size: 1em;
}
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="https://unpkg.com/cytoscape@3.1.0/dist/cytoscape.min.js"></script>

<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/cytoscape-cose-bilkent@4.0.0/cytoscape-cose-bilkent.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse@3.1.1/cytoscape-expand-collapse.js"></script>
<div id="cy"></div>

示例中的节点具有位置只是因为它是从另一个工具导出的。

每次执行展开或折叠操作时,如果设置了 layoutBy 选项,该布局将应用于图表。在示例中,layoutBy 选项设置为 cose-bilkent,这就是位置发生变化的原因。

我相信你可以通过将 layoutBy 设置为 null,将 fisheye 设置为 false 来实现你想要的。您可以看到其他选项及其解释 here.

P.S:初始坐标可以考虑设置Cytoscape的layout选项,而initializing.