我想在两个不同的SVG中在单个页面中实现两个强制布局。我为不同的功能创建了不同的对象。
//object for handling
var forceGraph = function(){
var force = d3.layout.force();
var width,height,vis;
var nodes = force.nodes();
var links = force.links();
this.disNodes = nodes;
this.disLinks = links;
var removedNodes = [];
var removedLinks = [];
var newNodes=[],newLinks=[];
this.setWidth = function(w){
width = w;
}
this.setHeight = function(h){
height = h;
}
this.setCanvas = function(c){
vis = c;
}
//adds new node to force.nodes of not existing in force.nodes
this.addNode = function(id){
if(!isNodeExisting(id)){
nodes.push({'id':id,'type':'circle'});
this.update();
}
}
//adds new square node to force.nodes
this.addSquareNode = function(id){
if(!isNodeExisting(id)){
nodes.push({'id':id,'type':'rect'});
this.update();
}
}
//remove extra nodes from force.nodes
this.removeNodes = function(switches,hosts){
var obj = this;
for(i=nodes.length-1;i>-1;i--){
if(switches.indexOf(nodes[i].id)==-1 && hosts.indexOf(nodes[i].id)==-1){
removedNodes.push(nodes[i]);
nodes.splice(i,1);
obj.update();
}
}
}
//removes extra links from force.links
this.removeLinks = function(){
var obj = this;
$.each(removedNodes,function(i,val){
for(i=links.length-1;i>-1;i--){
if(links[i].source.id==val.id || links[i].target.id==val.id){
var temp = links.splice(i,1);
removedLinks.push(temp[0]);
obj.update();
}
}
});
removedNodes.splice(0,removedNodes.length);
}
//determines if node is existing in force.nodes
var isNodeExisting = function(id){
for (var i in nodes) {
if (nodes[i]["id"] === id) return true;
}
return false;
}
//determines if links is existing force.links
var isLinkExisting = function(linkId){
for (var i in links) {
if (links[i].linkId === linkId) return true;
}
}
//adds a link to force.links if link is not existing
this.addLink = function(source,target,linkId){
if(!isLinkExisting(linkId)){
links.push({
'source':findNode(source),
'target':findNode(target),
'linkId':linkId
});
this.update();
}
}
//returns index of switch by taking its id
var findNode = function (id) {
for (var i in nodes) {
if (nodes[i]["id"] === id) return nodes[i];
};
};
var dragstart= function(d) {
d3.select(this).classed("fixed", d.fixed = true);
}
var dblclick = function(d){
d3.select(this).classed("fixed",d.fixed=false);
}
var displayHintText = function(d){
d3.select(this).select('.hintText').text(d.id);
}
var hideHintText = function(d){
d3.select(this).select('.hintText').text('');
}
//bring nodes to top of links.
this.keepNodesOnTop =function() {
$(".node").each(function(index) {
this.parentNode.appendChild(this);
});
}
var drag = force.drag()
.on('dragstart',dragstart);
this.update = function(){
link = vis.selectAll('.link')
.data(links,function(d){ return d.linkId});
//remove extra links from SVG
link.exit().remove();
//add extra links to SVG
link.enter()
.append('line')
.attr('class','link');
var node = vis.selectAll('g')
.data(nodes,function(d){return d.id});
//remove extra nodes from SVG
node.exit().remove();
//add extra nodes to SVG
var nodeEnter = node.enter()
.append('g')
.attr('class','node')
.on('dblclick', dblclick)
.on('mouseover',displayHintText)
.on('mouseout',hideHintText)
.call(drag);
//append text element to node group element
nodeEnter.append('text')
.attr('class','hintText');
//append circle to node group element
nodeEnter.append(function(d){
if(d.type=='circle'){
return document.createElementNS("http://www.w3.org/2000/svg",d.type);
}else if(d.type=='rect'){
return document.createElementNS("http://www.w3.org/2000/svg",d.type);
}
}).attr('class','node')
.each(function(d){
if(d.type=='circle'){
d3.select(this).attr({
r:8,
});
}else if(d.type=='rect'){
d3.select(this).attr({
width:16,
height:16
});
}
});
force.on('tick',function(e){
node.attr("transform", function (d) {
if(d.index==0){
damper = 0.1;
d.x = d.x + (width/3 - d.x) * (damper + 0.71) * e.alpha;
d.y = d.y + (height/3 - d.y) * (damper + 0.71) * e.alpha;
}
d.x = Math.min(width,Math.max(d.x,10));
d.y = Math.min(height,Math.max(d.y,10));
return "translate(" + d.x + "," + d.y + ")";
});
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;
})
.attr("id",function(d){
return d.linkId;
})
});
force.gravity(0.06)
.charge(-1000)
.linkDistance( function(d) { return 90 } )
.size([width, height])
.start();
}
};
我能够获得两个不同的动力图(draggale),但问题是只有最新绘制的图形链接才能连接到节点。前图是动态的,但链接是静态的。
我在下面提到了链接,他们没有工作: Multiple instances of d3 force layout on the same page Multiple force-layout graphs with d3 in seperate svg/div's
答案 0 :(得分:1)
在update()
函数中,我定义了link
而没有var
,因为它在全球范围内可用,并且始终采用最新的图形链接。将其更改为var link
工作正常。