当通过cytoscape.js-expand-collapse使用Ajax请求子数据时,展开组节点行为很奇怪。

时间:2019-02-15 12:32:09

标签: javascript layout expand cytoscape.js

我正在学习cytoscape.js及其相关扩展名cytoscape.js-expand-collapse,并被其惊人的功能所吸引。

我试图做一个演示,打开一个节点时,从服务器请求带有ajax的子节点并扩展组。

我发现扩展名cytoscape.js-expand-collapse具有提示功能。当一个节点具有子节点时,它将显示一个提示图标。

在我的演示中,扩展子节点之前我不知道其子节点。所以我在初始状态附加了一个虚拟节点。

展开节点时,我必须删除虚拟节点,请求真正的子节点,追加到组中并重新绘制图。

我该如何进行中继?我发现两种方法。一种方法是调用扩展名的expand API,另一种方法是调用cy.layout()。两种方法都不令人满意。

如果我使用expand的{​​{1}}方法扩展节点,则整个图形将始终在屏幕上移动,甚至飞出屏幕。

cytoscape.js-expand-collapse

如果我使用param.options.layoutBy = { name: 'cose-bilkent', fit: false, randomize: false, idealEdgeLength : 150 }; api.expand(param.nodes, param.options); 展开节点,则布局看起来不错,但是提示图标是错误的。 (展开节点时,它应显示减号图标而不是加号图标)

cy.layout({name:'cose-bilkent'})

我需要的是结合优势!展开节点时,布局看起来不错,并且提示图标正确。

查看我的演示。 更新演示以解决一些问题,现在我的演示可以正常工作了。

var layout = cy.layout({
    name: 'cose-bilkent',
    fit: false,
    randomize: false,
    idealEdgeLength : 150
});
layout.run();
document.addEventListener('DOMContentLoaded', function(){
				initGraph();
			});
			
			function initGraph(){
				var cy = window.cy = cytoscape({
					container: document.getElementById('cy'),

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

					style: [
						{
							selector: 'node',
							style: {
								'background-color': '#ad1a66',
								'label':'data(name)',
							}
						},

						{
							selector: ':parent',
							style: {
								'background-opacity': 0.333
							}
						},

						{
							selector: "node.cy-expand-collapse-collapsed-node",
							style: {
								"background-color": "darkblue",
								"shape": "rectangle"
							}
						},

						{
							selector: 'edge',
							style: {
								'width': 3,
								'line-color': '#ad1a66'
							}
						}
					],

					elements: initData()
				});
				
				initListeners();
        
        cy.on('layoutstop', centerGraph);
		function centerGraph(){
			cy.center();
			cy.off('layoutstop', centerGraph);
		}
			}
			
			
			function initData(){
				var me = this, i;
				
				var groupNum = 5, groups = [], dummy = [], edges = [];
				for(i = 0; i < groupNum; i++){
					groups.push({
						group:'nodes', 
						data:{
							id:'group'+i, 
							name:'group'+i
						}
					});
					dummy.push({// Insert dummy node in order to show cue icon.
						group:'nodes', 
						data:{
							id:'dummy'+i,
          name:'dummy'+i,
							parent : 'group'+i
						}
					});
				}
				var s,t;
				for(i = 0; i < groupNum - 1; i++){
					s = dummy[i].data.id;
					for(j = i+1; j < groupNum; j++){
						t = dummy[j].data.id;
						edges.push({"group":'edges',data:{"id":s+"_"+t, source:s, target:t}});
					}
				}
				return groups.concat(edges).concat(dummy);
			}
			
			function initListeners(){
				var ur = cy.undoRedo();
		ur.action("expand", function(param){
			var collapsedChildren = param.nodes._private.data.collapsedChildren;
			if(collapsedChildren 
					&& collapsedChildren.length == 1
					&& collapsedChildren[0]._private.data.id.indexOf('dummy') >= 0){
				openTargetNode(param.nodes);
				param.options.layoutBy = {
			  			name: 'cose-bilkent',
						fit: false,
						randomize: false,
						idealEdgeLength : 150
			  		};
				if(document.getElementById('switch').checked){
					var layout = cy.layout({
		  			name: 'cose-bilkent',
					fit: false,
					randomize: false,
					idealEdgeLength : 150
		  		});
				layout.run();
				return;
				}
				
			}else{
				param.options.layoutBy = null;
			}
			param.options.layoutBy = {
		  			name: 'cose-bilkent',
					fit: false,
					randomize: false,
					idealEdgeLength : 150
		  		};
			api.expand(param.nodes, param.options);
		});
		ur.action("collapse", function(param){
			param.options.layoutBy = {
		  			name: 'cose-bilkent',
					fit: false,
					randomize: false,
					idealEdgeLength : 150
		  		};
			api.collapse(param.nodes, param.options);
		});
			}
			
			
			function openTargetNode(target){
		var me = this;
  		var targetPosition = target.position();
  		var childNum = 5, innerLinks = 10, i, j, counter = 0;
  		
  		for(i = 0; i < childNum; i++){
  			cy.add({
  				group: 'nodes', 
  				data: { id: target.id() + i, name: target.id() + i, parent: target.id() }, 
  				position:{x:targetPosition.x, y: targetPosition.y}
  			});
  		}
  		for(i = 0; i < childNum - 1; i++){
  			s = target.id() + i;
  			for(j = i + 1; j < childNum && counter++ < innerLinks; j++){
	  			t = target.id() + j;
	  			cy.add({ 
	  				group: 'edges', 
	  				data: { id: s+"-"+t, source: s, target: t }
	  			});
	  		}
  		}
  		
  		var neighborhood = target.neighborhood(), nodes = [];
  		for(i = 0; i <neighborhood.length; i++){
  			if(target.neighborhood()[i].isNode()){
  				nodes.push(target.neighborhood()[i]._private.data.id);
  			}
  		}
  		
  		var s, t, j = 0;
  		for(i = 0; i < nodes.length; i++){
  			s = target.id() + (j++)%childNum;
  			t = nodes[i];
  			cy.add({
  				group: 'edges', 
  				data: { id: s+"-"+t, source: s, target: t }
  			});
  		}
  		
  		cy.remove(cy.$('#' + target._private.data.collapsedChildren[0]._private.data.id));
  		cy.remove(target.connectedEdges());
	}
	
	function switchHandler(a, b){
		initGraph();
	}
body {
				font-family: helvetica neue, helvetica, liberation sans, arial, sans-serif;
				font-size: 14px;
			}

			#cy {
				z-index: 999;
				width: 85%;
				height: 85%;
				float: left;
			}

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

0 个答案:

没有答案