d3.js-添加新节点后图形被破坏 [英] d3.js - graph is broken after adding new nodes
问题描述
我使用以下逻辑构建以下图形:
I build the graph below with the following logic:
- 将鼠标悬停在节点上-它是未连接的节点&它们的链接是透明的.
- 将鼠标悬停在链接上-所有节点&链接是透明的,除了触摸的链接(变为粗体)和两个节点.
这很好,直到我尝试向图中添加更多节点.按下添加节点按钮,添加另一个节点,并链接到该聚会.问题在于,节点逻辑已损坏(链接逻辑仍然有效). 知道为什么吗?
That works great, until I try to add more nodes to the graph. Press on the Add Node button, adds another node and it's link to the party. The problem is, that the node logic is broken (the link logic still work). Any idea why?
谢谢! JSFiddle
function removeNodePopup() {
$("#nodePopup").remove();
}
function showNodePopup(node) {
removeNodePopup();
if (!node['data']) {
return;
}
var data = node['data'];
var htmlStr = '';
htmlStr += '<div id="nodePopup" >';
htmlStr += ' <div><button id="nodePopupCloseButton" type="button" class="close" data-dismiss="alert"><span class="glyphicon glyphicon-remove" style="font-size: 13px;"> </span> </div>';
htmlStr += ' <div class="nodePopupName">' + data['name'] + '</div>';
if (data['desc']) {
if (data['desc'].startsWith("http")) {
htmlStr += ' <a class="nodePopupLink" href="' + data['desc'] + '" target="_blank">Go to post..</a>';
}
else {
htmlStr += ' <div class="nodePopupDesc">' + data['desc'] + '</div>';
}
}
htmlStr += ' <div class="nodePopupGroup">GROUP: ' + data['groupId'] + '</div>';
htmlStr += ' <div class="nodePopupLeader">LEADER: ' + data['leaderId'] + '</div>';
htmlStr += ' <div class="nodePopupImage"><img src="' + node['image'] + '" style="width: 130px;" /></div>';
htmlStr += '</div>';
$("body").append(htmlStr);
$("#nodePopupCloseButton").click(removeNodePopup);
}
const LINK_DEFAULT_COLOR = "#ccc";
const NODE_DEFAULT_COLOR = "gray";
const DEFAULT_OPACITY = 1;
const BACKGROUND_OPACITY = 0.2;
function Graph(elementId) {
var svg;
var simulation;
var mNodesData = [];
var mEdgesData = [];
var mNode = null;
var mLink = null;
var elementId;
var heightDelta = 100;
var width = window.innerWidth;
var height = window.innerHeight - heightDelta;
return {
init: function () {
svg = d3.select('#' + elementId)
.append("svg")
.attr("width", width)
.attr("height", height);
simulation = d3.forceSimulation()
.force(".edge", d3.forceLink())
.force("charge", d3.forceManyBody().strength(-600))
.force("center", d3.forceCenter(width / 2, height / 2));
mLink = svg.selectAll(".edge")
.attr("class", "edge")
.style("stroke", LINK_DEFAULT_COLOR)
.style("stroke-width", function (e) {
return 1
/* e.width*/
});
mNode = svg.selectAll(".node")
.attr("class", "node");
},
clearGraph: function () {
$('#' + this.elementId).empty();
},
getNodes: function () {
return mNodesData;
},
getEdges: function () {
return mEdgesData;
},
addNodes: function (nodes) {
mNodesData = mNodesData.concat(nodes);
},
addEdges: function (edges) {
mEdgesData = mEdgesData.concat(edges);
},
onMouseOut: function () {
// removePopup();
mNode.select("image").style("opacity", DEFAULT_OPACITY);
mNode.select("circle").style("stroke", NODE_DEFAULT_COLOR);
mLink.style("opacity", DEFAULT_OPACITY).style("stroke", LINK_DEFAULT_COLOR);
},
draw: function () {
mNode = svg.selectAll(".node")
.data(mNodesData)
.enter()
.append("g")
.attr("class", "node").
merge(mNode);
mLink = svg.selectAll(".edge")
.data(mEdgesData)
.enter()
.append("line")
.attr("class", "edge")
.style("stroke", LINK_DEFAULT_COLOR)
.style("stroke-width", function (e) {
return 2
/* e.width*/
}).merge(mLink).lower();
mNode.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
mNode.on('mouseover', function (thisNode) {
showNodePopup(thisNode);
var thisNodeID = thisNode.id;
var connectedNodes = mEdgesData.filter(function(d) {
return d.source.id === thisNodeID || d.target.id === thisNodeID
}).map(function(d) {
return d.source.id === thisNodeID ? d.target.id : d.source.id
});
mNode.each(function (otherNode, id) {
var image = d3.select(this).select("image");
var circle = d3.select(this).select("circle");
if (connectedNodes.indexOf(otherNode.id) > -1 || thisNodeID == otherNode.id) {
image.style("opacity", DEFAULT_OPACITY);
circle.style("stroke", NODE_DEFAULT_COLOR);
}
else {
image.style("opacity", BACKGROUND_OPACITY);
circle.style("stroke", "#f6f6f6");
}
});
// var filteredNodes = mNode.filter(function(otherNode) {
// return connectedNodes.indexOf(otherNode.id) == -1
// });
//
// filteredNodes.select("image").style("opacity", BACKGROUND_OPACITY);
// filteredNodes.select("circle").style("stroke", "#f6f6f6");
//
// var unfilterdNode = mNode.filter(function (otherNode) {
// return connectedNodes.indexOf(otherNode.id) > -1 || thisNodeID == otherNode.id;
// });
// unfilterdNode.select("image").style("opacity", DEFAULT_OPACITY);
// unfilterdNode.select("circle").style("stroke", NODE_DEFAULT_COLOR);
mLink.filter(function (otherLink) {
return (thisNode !== otherLink.source && thisNode !== otherLink.target);
}).style("opacity", BACKGROUND_OPACITY);
mLink.filter(function (otherLink) {
return (thisNode == otherLink.source || thisNode == otherLink.target);
}).style("opacity", DEFAULT_OPACITY);
})
.on('mouseout', this.onMouseOut);
mLink.on('mouseover', function (currentLink) {
mLink.filter(function (otherLink) {
return (currentLink == otherLink);
}).style("stroke", "black");
mLink.filter(function (otherLink) {
return (currentLink !== otherLink);
}).style("opacity", BACKGROUND_OPACITY);
mNode.filter(function (otherNode) {
return (currentLink.source != otherNode || currentLink.target != otherNode);
}).select("image").style("opacity", BACKGROUND_OPACITY);
mNode.filter(function (otherNode) {
return (currentLink.source != otherNode || currentLink.target != otherNode);
}).select("circle").style("stroke", "#f6f6f6");
mNode.filter(function (d1) {
return (d1 == currentLink.source || d1 == currentLink.target);
}).select("image").style("opacity", DEFAULT_OPACITY);
mNode.filter(function (d1) {
return (d1 == currentLink.source || d1 == currentLink.target);
}).select("circle").style("stroke", NODE_DEFAULT_COLOR);
}).on('mouseout', this.onMouseOut);
var nodeCircle = mNode.append("circle")
.attr("r", function (d) {
return 0.5 * Math.max(d.width, d.height)
})
.attr("stroke", NODE_DEFAULT_COLOR)
.attr("stroke-width", "2px")
.attr("fill", "white");
var nodeImage = mNode.append("image")
.attr("xlink:href", function (d) {
return d.image
})
.attr("height", function (d) {
return d.height + ""
})
.attr("width", function (d) {
return d.width + ""
})
.attr("x", function (d) {
return -0.5 * d.width
})
.attr("y", function (d) {
return -0.5 * d.height
})
.attr("clip-path", function (d) {
return "circle(" + (0.48 * Math.max(d.width, d.height)) + "px)"
});
simulation.nodes(mNodesData);
simulation.force(".edge").links(mEdgesData);
simulation.on("tick", function () {
mLink.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;
})
mNode.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")"
});
mNode.attr("cx", function (d) {
return d.x = Math.max(d.width, Math.min(width - d.width, d.x));
})
.attr("cy", function (d) {
return d.y = Math.max(d.height, Math.min(height - heightDelta - d.height, d.y));
});
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
}
}
}
initialData = {
"nodes": [{
"id": 0,
"image": "images/0.jpg",
"height": 40,
"width": 40,
"data": {
"name": "Number0",
"groupId": "Bla1",
"desc": "Desc1",
"leaderId": "123-123"
}
}, {
"id": 1,
"image": "images/1.jpeg",
"height": 100,
"width": 100,
"data": {
"name": "Number1",
"groupId": "Bla2",
"desc": "Desc1",
"leaderId": "123-123"
}
}, {
"id": 2,
"image": "images/2.png",
"height": 50,
"width": 50,
"data": {
"name": "Number2",
"groupId": "Bla3",
"desc": "Desc1",
"leaderId": "123-123"
}
}, {
"id": 3,
"image": "images/3.jpeg",
"height": 40,
"width": 40,
"data": {
"name": "Number3",
"groupId": "Bla4",
"desc": "Desc1",
"leaderId": "123-123"
}
}],
"edges": [{
"source": 0,
"target": 1,
"width": 5,
"data": {
"counter": 500
}
}, {
"source": 0,
"target": 2,
"width": 10,
"data": {
"counter": 500
}
}, {
"source": 0,
"target": 3,
"width": 1,
"data": {
"counter": 500
}
}]
};
var graph = Graph('d3Graph');
graph.init();
graph.addNodes(initialData.nodes);
graph.addEdges(initialData.edges);
graph.draw();
//add();
function add() {
graph.addNodes([{
"id": 4,
"image": "images/4.jpg",
"height": 20,
"width": 20,
"data": {
"name": "Number4",
"groupId": "Bla4",
"desc": "Desc4",
"leaderId": "1234-1234"
}
}]);
graph.addEdges([{
"source": 4,
"target": 3,
"width": 1,
"data": {
"counter": 500
}
}])
graph.draw();
}
推荐答案
您多次调用了draw
方法,因此必须谨慎对待.
You called draw
method multiple times, so you have to treat it carefully.
仅应添加新添加的节点image
和circle
标签,
所以你应该改变
Only newly added nodes are supposed to be added image
and circle
tags,
so you should change
mNode = svg.selectAll(".node")
.data(mNodesData)
.enter()
.append("g")
.attr("class", "node").
merge(mNode);
到
var newNodes = svg.selectAll(".node")
.data(mNodesData)
.enter()
.append("g")
.attr("class", "node");
mNode=newNodes.merge(mNode);
并更改
var nodeCircle = mNode.append("circle")
到
var nodeCircle = newNodes.append("circle")
和image
相关代码应该以相同的方式更改.
And image
related code are supposed to be changed in same manner.
这篇关于d3.js-添加新节点后图形被破坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!