使用 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>
最后总结一下我需要的:
带有一些节点的初始化图,可以根据 属性 类型进行扩展。 type=1 的节点是可扩展的,type=2 的节点不是。
所有节点做合理布局,如layoutBy:{name:'cose-bilkent'}
展开一个节点(如:A)时,发送ajax请求获取子节点(如:A1、A2、A3),然后布局子节点。该图可能需要适当的调整。我希望是增量布局,而不是完全重新布局。
折叠之前的复合节点(A组A1,A2,A3)时,图上的所有节点都保持之前的位置。
展开最后一个组节点(如: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.
我一直在寻找一个好的拓扑布局 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>
最后总结一下我需要的:
带有一些节点的初始化图,可以根据 属性 类型进行扩展。 type=1 的节点是可扩展的,type=2 的节点不是。
所有节点做合理布局,如layoutBy:{name:'cose-bilkent'}
展开一个节点(如:A)时,发送ajax请求获取子节点(如:A1、A2、A3),然后布局子节点。该图可能需要适当的调整。我希望是增量布局,而不是完全重新布局。
折叠之前的复合节点(A组A1,A2,A3)时,图上的所有节点都保持之前的位置。
展开最后一个组节点(如: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.