1. 程式人生 > >d3.js實現雙擊刪除節點並刪除節點上的文字

d3.js實現雙擊刪除節點並刪除節點上的文字

最近專案遇到一個問題:刪除節點,節點上的文字卻無法刪除。

經過F12的除錯,我發現原來自己寫的節點、連線、文字分別包裹在不同的g標籤內。

於是出現了兩種解決方案:

(1)把文字依附在節點上

(2)選中節點的時候遍歷文字確保是哪個文字和該節點是對應的

我個人認為第一種方案是最優化的,我也推薦大家遇到這個問題採用第一種方案。 

但是我專案之前寫的結構就這樣了,如果現在改的話,需要改的程式碼太多,於是我採用第二種方案。

廢話之後,乾貨奉上

以下是我寫的一個demo:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>雙擊刪除節點</title>
		<script src="http://d3js.org/d3.v3.min.js"></script>  
	</head>
	<body>
		<script>
			var width = 1366;
			var height = 768;
			var img_w = 77;
			var img_h = 80;
        	var radius = 30;
			var svg = d3.select("body")
						.append("svg")
						.attr("width",width)
						.attr("height",height);
   			d3.json("json/song.json",function(error,data){
   				if(error){
   					return console.log(error);
   				}
   			var dataset = data;
   			console.log(dataset);
   			
   			var force = d3.layout.force()
   						  .nodes(dataset.nodes)
   						  .links(dataset.links)
   						  .size([width,height])
   						  .linkDistance(100)
   						  .charge(-1500)
   						  .start();
   						  
   			var links = svg.selectAll("line")
   						   .data(dataset.links)
   						   .enter()
   						   .append("line")
   						   .attr("class","lines")
   						   .attr("style","stroke: #CCCCCC; stroke-width: 2;");

			var nodes = svg.selectAll("circle")
						   .data(dataset.nodes)
						   .enter()
						   .append("circle")
						   .attr("r",radius)
						   .attr("class","nodes")
						   .attr("fill","pink")
						   .on("dblclick",function(d){
						   		//雙擊節點刪除,獲取選中節點的在json中的name的值
						   		d3.select(this).remove();
						   		var clickNodeName = d.name;//點選節點的名字
						   		d3.selectAll(".nodetext").each(function(d,i){
						   			var temp = d.name;
						   			if(temp==clickNodeName){
//						   				alert("相等");
						   				d3.select(this).remove();
						   			}
						   		});
						   		d3.selectAll(".lines").each(function(e){
						   			if(e.source===d||e.target===d){
						   				d3.select(this).remove();
						   			}
						   		})
						   })
                       	   .on("mouseout",function(d,i){
                       			nodes.style("stroke",function(edge){
                       				if(edge.source===d){
                       					return "#CCCCCC";
                       				}
                       			});
                                links.style("stroke","#CCCCCC");
	                       })
						   .call(force.drag);
					   
			var text_dx = -20;
			var text_dy = 20;
			console.log("x:"+text_dx);
			console.log("y:"+text_dy);
			
			var nodes_text = svg.selectAll(".nodetext")
							.data(dataset.nodes)
							.enter()
							.append("text")
							.attr("class","nodetext")
							.attr("dy",".35em")
							.attr("text-anchor","middle")
						    .text(function(d) { return d.name; });
			force.on("tick", function() {  
				
				links.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; });
				
				nodes.attr("cx", function(d) { return d.x; })  
				     .attr("cy", function(d) { return d.y; });  
				
				nodes_text.attr("dx", function(d) { return d.x-img_w/4; })
				     	 .attr("dy", function(d) { return d.y+5; }); 
			});  
   		});
		</script>
	</body>
</html>

json檔案如下:

{
   				"nodes":[
   						 {"name":"人物1","group":3,"img":"img/1.jpg"},
   						 {"name":"人物2","group":3,"img":"img/2.jpg"},  
						 {"name":"人物3","group":3,"img":"img/3.jpg"},  
						 {"name":"人物4","group":3,"img":"img/4.jpg"},
						 {"name":"人物5","group":3,"img":"img/5.jpg"},
						 {"name":"人物6","group":2,"img":"img/6.jpg"},  
   						 {"name":"人物7","group":2,"img":"img/7.jpg"},  
						 {"name":"人物8","group":2,"img":"img/8.jpg"},  
						 {"name":"人物9","group":2,"img":"img/9.jpg"},
						 {"name":"人物10","group":2,"img":"img/10.jpg"},
						 {"name":"人物11","group":1,"img":"img/11.jpg"},
						 {"name":"人物12","group":1,"img":"img/12.jpg"},
						 {"name":"人物13","group":1,"img":"img/13.jpg"},
						 {"name":"人物14","group":1,"img":"img/14.jpg"},
						 {"name":"人物15","group":1,"img":"img/15.jpg"},
						 {"name":"人物16","group":1,"img":"img/16.jpg"}],
   				"links":[{"source":0,"target":1,"relation":"\ue900 \ue904 \ue908 \ue9a1"},  
				         {"source":0,"target":2,"relation":"關係一"},
				         {"source":0,"target":3,"relation":"關係二"},
				         {"source":0,"target":4,"relation":"\ue909"},
				         {"source":5,"target":6,"relation":"\ue9a1"},  
				         {"source":5,"target":7,"relation":"\ue9a2"},
				         {"source":5,"target":8,"relation":"\ue9a3"},
				         {"source":5,"target":9,"relation":"\ue9ad"}, 
				         {"source":10,"target":11,"relation":"\ue9c1"},
				         {"source":10,"target":12,"relation":"\ue9c3"},
				         {"source":10,"target":13,"relation":"\ue9dd"},
				         {"source":10,"target":14,"relation":"\ue9fd"},
				         {"source":10,"target":15,"relation":"\ue9ed"},
				         {"source":10,"target":11,"relation":"\ue91d"},
				         {"source":0,"target":5,"relation":"\ue93d"},
				         {"source":5,"target":10,"relation":"\ue95d"},
				         {"source":10,"target":0,"relation":"\ue97d"}
				       ] 
   			}

測試效果如下: