D3 v3版本繪製力導向圖更新節點時JS控制檯報錯 :Error: attribute cx: Expected length, "NaN"解決辦法

D3的v3版本,很古老了。

拿來繪製力導向圖,畫布初始化的代碼如下:

//代碼不完整,僅作演示以說明問題
//節點數組
	var nodes = [ { name: "sssss" ,phone:"18888888888"}, { name: "vvvv" ,phone:"199999999"},{ name: "ggggg" ,phone:"20000000"} ];
	//連線數組
	var edges = [ { source : 0 , target: 1 },{ source : 1 , target: 0 }];
//設置畫布
		var width = 1000;  //畫布的寬度
		var height = 1000;   //畫布的高度

		var svg = d3.select("body")     //選擇文檔中的body元素
		    .append("svg")          //添加一個svg元素
		    .attr("width", width)       //設定寬度
		    .attr("height", height);    //設定高度
		  

		//定義力導向圖佈局
		var force = d3.layout.force()
      		.nodes(nodes) //指定節點數組
      		.links(edges) //指定連線數組
      		.size([width,height]) //指定作用域範圍
      		.linkDistance(150) //指定連線長度
      		.charge([-400]); //相互之間的作用力
		
		//力學作用生效
		force.start();    //開始作用
		//添加連線 
		 var svg_edges = svg.selectAll("line")
		     .data(edges)
		     .enter()
		     .append("line")
		     .style("stroke","#ccc")
		     .style("stroke-width",1);

		 var color = d3.scale.category20();

後來我往節點數組nodes末尾push了一個新元素,再次重繪此力導向圖,代碼如下:

//添加新節點,重繪力導向圖的代碼
function reGraph(){
			 nodes.push({name: "ffffuuuuucccckkk" ,phone:"18888888888"});
			 edges.push({source : 0 , target: 3});
			//添加節點 
			 var svg_nodes = svg.selectAll("circle")
			     .data(nodes)
			     .enter()
			     .append("circle")
			     .attr("r",20)
			     .style("fill",function(d,i){   //設置填充顏色
			         return color(i);
			     })
			     .on("click", function(d,i){     //添加點擊事件
			    	 alert("這是"+d.name+",電話:"+d.phone);
			     })
			     .call(force.drag);  //使得節點能夠拖動

			 //添加描述節點的文字
			 var svg_texts = svg.selectAll("text")
			     .data(nodes)
			     .enter()
			     .append("text")
			     .style("fill", "black")
			     .attr("dx", 20)
			     .attr("dy", 8)
			     .text(function(d){
			        return d.name;
			     });
			 force.on("tick", function(){ //對於每一個時間間隔
				    //更新連線座標
				    svg_edges.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_nodes.attr("cx",function(d){ return d.x; })
				        .attr("cy",function(d){ return d.y; });

				    //更新文字座標
				    svg_texts.attr("x", function(d){ return d.x; })
				       .attr("y", function(d){ return d.y; });
				 });
		 }

就報了幾千個錯:

<circle> attribute cx: Expected length, “NaN”

Error: <circle> attribute cx: Expected length, "NaN".

等諸多類似錯誤,都是告訴我屬性缺失。

研究了很久,最後發現問題所在:

指定的節點數組不能直接拿來用作繪圖數據。

需要通過force這個轉換器轉換之後才能作爲數據使用。

因此直接push新元素進數組然後刷新力導向圖是不可行的,新元素沒經過force的處理,缺失了很多屬性,故報上述錯誤。

因此解決辦法如下:

1.新建一個節點數組及連線數組,將之前數組的數據如name,phone等自己設定的屬性拷貝到新數組

2.新數組push你要添加的元素

3.重新初始化力導向圖,這段代碼尤其重要:

//定義力導向圖佈局
		var force = d3.layout.force()
      		.nodes(nodes) //指定節點數組
      		.links(edges) //指定連線數組
      		.size([width,height]) //指定作用域範圍
      		.linkDistance(150) //指定連線長度
      		.charge([-400]); //相互之間的作用力
		
		//力學作用生效
		force.start();    //開始作用

因爲新增的元素一樣需要經過force的轉換處理才能作爲繪製節點的數據使用,具體見以下博主的這段話

如何理解佈局

從上面的圖可以看到,佈局的作用是:將不適合用於繪圖的數據轉換成了適合用於繪圖的數據。因此,爲了便於初學者理解,將佈局的作用解釋成:數據轉換。

佈局有哪些

D3 總共提供了 12 個佈局:餅狀圖(Pie)、力導向圖(Force)、弦圖(Chord)、樹狀圖(Tree)、集羣圖(Cluster)、捆圖(Bundle)、打包圖(Pack)、直方圖(Histogram)、分區圖(Partition)、堆棧圖(Stack)、矩陣樹圖(Treemap)、層級圖(Hierarchy)。

12 個佈局中,層級圖(Hierarchy)不能直接使用。集羣圖、打包圖、分區圖、樹狀圖、矩陣樹圖是由層級圖擴展來的。如此一來,能夠使用的佈局是 11 個(有 5 個是由層級圖擴展而來)。這些佈局的作用都是將某種數據轉換成另一種數據,而轉換後的數據是利於可視化的。
————————————————
版權聲明:本文爲CSDN博主「Lelliam」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_31052401/article/details/93786425

然後接上述重繪代碼即可。

總結:本次錯誤原因是節點數組、連線數組新增元素後,未做轉換處理直接拿來繪圖,而我們知道,未經轉換器處理的數據是無法用於繪圖的,會導致很多繪圖必須的屬性缺失,因此,需將數組拷貝後重新用轉換器如force(此處是力導向圖,僅用force說明問題)轉換後重繪,就不會導致屬性缺失了。

--------end------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章