首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >打开组后的新布局不是基于使用cola.js的上一个布局

打开组后的新布局不是基于使用cola.js的上一个布局
EN

Stack Overflow用户
提问于 2018-12-13 13:30:48
回答 1查看 496关注 0票数 5

我最近了解到一个很棒的JS库cola.js。它可以进行部队布局和支持团队。点击此处了解更多信息:Cola.js

我创建了一个简单的demo来展示一个带有开放分组功能的力布局。但我对开场白的行为感到困惑。

我认为当打开一个群组时,新的布局应该是在上一个布局的基础上做了一些小的调整。但现在它重新布局了所有节点。为什么?

我从这个链接中学到了一些理想:Offical Demo : Online Graph Exploration,它看起来非常复杂。动态添加到图中的新节点的坐标应设置为开口组的坐标。不幸的是,它也不能解决我的问题。

以下是我的demo:

代码语言:javascript
复制
var w = 480, h = 420, cola;
var data = {
	"nodes": [
		{"name": "Top","width": 60,"height": 60},
		{"name": "A","width": 60,"height": 60},
		{"name": "B","width": 60,"height": 60},
		{"name": "C","width": 60,"height": 60},
		{"name": "D","width": 60,"height": 60},
		{"name": "E","width": 60,"height": 60},
		{"name": "F","width": 60,"height": 60},
		{"name": "G","width": 60,"height": 60},
		{"name": "H","width": 60,"height": 60},
		{"name": "I","width": 60,"height": 60}
	],
	"links": [
		{"source": 0,"target": 6},
		{"source": 0,"target": 4},
		{"source": 0,"target": 3},
		{"source": 0,"target": 7},
		{"source": 0,"target": 8},
		{"source": 6,"target": 0},
		{"source": 6,"target": 7},
		{"source": 4,"target": 0},
		{"source": 4,"target": 3},
		{"source": 3,"target": 0},
		{"source": 3,"target": 4},
		{"source": 7,"target": 0},
		{"source": 7,"target": 6},
		{"source": 7,"target": 4},
		{"source": 8,"target": 0},
		{"source": 8,"target": 7}
	],
	"groups": [
		{"leaves": [0,1,2],"groups": [1],"name": "Product"},
		{"leaves": [7],"name": "Businness"},
		{"leaves": [3,4,6,8,9],"name": "Tech"}
	]
};

cola = cola.d3adaptor()
		.linkDistance(150)
		.avoidOverlaps(true)
	    .handleDisconnected(true)
		.size([w, h]);
	
	svg = d3.select("body").append("svg")
		.attr("width", w)
		.attr("height", h)
		.on("dblclick.zoom", null);
	
	svg.append('rect')
		.attr("width", w)
		.attr("height", h)
		.style("fill", "none")
		.style("pointer-events", "all");
	
	svg = svg.append('g');
	
	update(data);

	cola.on("tick", function () {
		svg.selectAll(".link")
			.attr("x1", function (d) { return d.source.x; })
			.attr("y1", function (d) { return d.source.y; })
			.attr("x2", function (d) { return d.target.x; })
			.attr("y2", function (d) { return d.target.y; });
		
		svg.selectAll(".nodeimage").attr("x", function(d){ return d.x - 25 / 2 }).attr("y", function(d){ return d.y - 25 / 2 });

		svg.selectAll(".group")
			.attr("x", function (d) { return d.bounds.x; })
			.attr("y", function (d) { return d.bounds.y; })
			.attr("width", function (d) { return d.bounds.width(); })
			.attr("height", function (d) { return d.bounds.height(); });
		
		svg.selectAll(".label").attr("x", function (d) {
				var w = this.getBBox().width;
				return d.x - w/2;
			})
			.attr("y", function (d) {
				var h = this.getBBox().height;
				return d.y + 25;
			});
		
		svg.selectAll('.groupclosebutton')
			.attr("x", function (d) { return d.bounds.x + d.bounds.width() - 20; })
			.attr("y", function (d) { return d.bounds.y + 2; });
		
		
		svg.selectAll('.groupname')
			.attr("x", function (d) { return d.bounds.x + 5; })
			.attr("y", function (d) { return d.bounds.y + 15; });
	});

function update(data){
	//data.groups.forEach(function (g) { g.padding = 15; });
	cola.nodes(data.nodes).links(data.links).groups(data.groups).start();

	var color = ['#d3d4e5', '#f7e0c8', '#dee8f2', '#cbe5c4', '#ededeb'];
	var group = svg.selectAll(".group").data(data.groups, function(d) { return d.name;});
	group.enter().append("rect")//, ":last-child"
		.attr("rx", 8).attr("ry", 8)
		.attr("class", "group")
		.style("fill", function (d, i) { return color[i%5]; })
		.call(cola.drag);
	group.exit().remove();
	
	var groupName = svg.selectAll(".groupname").data(data.groups, function(d) { return d.name;});
	groupName.enter().append("text")
		.attr("class", "groupname")
		.attr("width", "40px")
		.attr("height", "13px")
		.text(function (d) { return d.name; });
	groupName.exit().remove();
	
	var link = svg.selectAll(".link").data(data.links, function(d) { return d.source.name+'-'+d.target.name;});
	link.enter().append("line").attr("class", "link").style("stroke", "rgb(168, 168, 168)");
	link.exit().remove();
	
	var nodes = svg.selectAll('.nodeimage').data(data.nodes, function(d) { return d.name;});
	nodes.enter().append('svg:image')
		.attr("class", "nodeimage")
		.call(cola.drag)
		.attr("xlink:href", function(d){
			var img = "http://icons.iconarchive.com/icons/hopstarter/sleek-xp-basic/24/Folder-icon.png";
			return img;
		})
		.attr('temp', function(d){
			var self = d3.select(this);
			self.attr("width", 25);
			self.attr("height", 25);
		})
		.on("dblclick", function(node, index, selection){
			d3.event.preventDefault();
			openGroup(node);
		});
	nodes.exit().transition().attr("width", 0).attr("width", 0).remove();
	
	var label = svg.selectAll(".label").data(data.nodes, function(d) { return d.name;});
	label.enter().append("text")
		.attr("class", "label")
		.attr("width", "40")
		.attr("height", 15)
		.text(function (d) { return d.name; })
		.call(cola.drag);
	label.exit().remove();
}

function openGroup(node){
	var i,j, flag,maxnodes = 3, groupDeletedIndex = -1;
	
	// Delete the node
	for(i = 0; i < this.data.nodes.length; i++){
		if(this.data.nodes[i].name == node.name){
			this.data.nodes.splice(i, 1);
			break;
		}
	}
	// Delete old links linked to the node
	for(i = this.data.links.length - 1; i >= 0; i--){
		if(this.data.links[i].source.name == node.name
				|| this.data.links[i].target.name == node.name){
			this.data.links.splice(i, 1);
		}
	}
	// Delete the relationship of the node
	flag = false;
	for(i = 0; i < this.data.groups.length; i++){
		for(j = 0; j < this.data.groups[i].leaves.length; j++){
			if(this.data.groups[i].leaves[j].name == node.name){
				this.data.groups[i].leaves.splice(j, 1);
				flag = true;
				groupDeletedIndex = i;
				break;
			}
		}
		if(flag)break;
	}
	
	// Create new nodes belong to openning group
	for(var i = 0; i < maxnodes; i++){
		var obj = { 
			name : node.name+'child'+i , 
			width : 100, 
			height : 100, 
			x:node.x, 
			y:node.y,
			px:node.px,
			py:node.py
		};
		this.data.nodes.push(obj);
		if(i%3!=0){
			this.data.links.push({// Create demo links
				source : this.data.nodes.length-1,
				target : Math.floor(Math.random(this.data.nodes.length-1)) 
			});
		}
	}
	// Create a group to contain the new nodes and push to groups
	this.data.groups.push({
		leaves : [], 
		name : node.name, 
		bounds : {x:node.x, y:node.y, X:node.x+100, Y:node.y+100},
		padding : 15
	});
	var begin = this.data.nodes.length - maxnodes;
	for(var i = 0; i < maxnodes; i++){
		this.data.groups[this.data.groups.length-1].leaves.push(begin+i);
	}
	
	if(groupDeletedIndex > -1){
		if(!this.data.groups[groupDeletedIndex].groups){
			this.data.groups[groupDeletedIndex].groups = [];
		}
		this.data.groups[groupDeletedIndex].groups.push(this.data.groups.length-1);
	}
	update(this.data);
}
代码语言:javascript
复制
<script src="https://marvl.infotech.monash.edu/webcola/cola.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<body/>

我的codepen演示也工作得很好:Cola open group demo

有没有可能根据上一次打开的状态重新布局?不是一个新的完整的重新布局?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-30 11:21:07

我问这个问题已经一个月了,但不幸的是,很少有人关注这个问题。

最近,我一直在学习如何用JavaScript库做一个合理的布局支持的组功能。我找到了一些库,比如D3WebColacytoscape.jsyfile

这里有一个比较D3 vs cytoscape的链接。基于此,我最终选择了cytoscape,因为它提供了更强大的API和合理的算法来布局复杂的关系。所以我对cola.js很抱歉。

cytoscape有许多扩展,可以做更好的布局工作。单击以下链接查看更多cytoscape.js-cose-bilkentcytoscape.js-expand-collapsecytoscape.js-cola

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53755497

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档