D3.js 以圓做點繪制力圖(一)
來源:程序員人生 發布時間:2014-11-24 08:42:17 閱讀次數:5993次
SVG是甚么?
如何在SVG上繪制1個圓?
如何在SVG上繪制1條線?
力圖的基本屬性有哪些?
這些問題將由本文來逐一解答。
在代碼方面,我們沿用上文的網頁框架,把body里面的js替換成現在的js便可。
SVG
SVG,可縮放的矢量圖,我們以后所繪制 的數據展現圖大都是在SVG這個大容器內完成的,它相當于畫布。創建SVG,就是有益于導出、保存繪制好的圖形。
簡單的SVG標簽格式 <svg width="500" height="50"></svg>,在SVG標簽中可以嵌入很多可見元素,包括 rect、circle、ellipse、line、text和path。
下面,我們在body中創建1個js標簽,在里面創建1個svg對象,代碼以下:
<span style="font-size:14px;">var w = 500;
var h = 500;
var svg = d3.select("body")
.append("svg")
.attr("width", w) //設置寬度
.attr("height", h); //設置高度
</span>
繪制圓
在svg內添加circle元素,先介紹下circle的基本屬性:cx 圓心x坐標 cy圓心y坐標 r半徑
接下來,繪制5個半徑順次增大的圓,并將它們的圓心放到同1條y軸上,代碼以下
<span style="font-size:14px;"> var dataset = [ 5, 10, 15, 20, 25 ];
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {//圓心坐標從左向右順次遞增,注意:i表示引入數據在數組的下標,如:d=5,i=0
return (i * 50) + 25;
})
.attr("cy", h/2) //將圓心放到svg高度中間
.attr("r", function(d) {//半徑
return d;
})</span>
緊接著設置各圓的屬性
<span style="font-size:14px;"> .attr("fill", "yellow") //給各圓填充黃色
.attr("stroke", "orange") //給各圓邊涂成橘黃
.attr("stroke-width", function(d) { //按比例設置邊的厚度
return d/2;
});
</span>
至此,SVG上的圓就繪制完成了見下圖

繪制線
在svg繪制1條線,首先要定義它的兩個端點,出發點和終點 (x1,y1)和(x2,y2)
線的基本屬性包括:
- x1 屬性在 x 軸定義線條的開始
- y1 屬性在 y 軸定義線條的開始
- x2 屬性在 x 軸定義線條的結束
- y2 屬性在 y 軸定義線條的結束
<span style="font-size:14px;">var line = svg.append('line')
.attr('x1',100)
.attr('y1',100)
.attr('x2',200)
.attr('y2',200)
.attr('style','stroke:rgb(99,99,99);stroke-width:2'); //描邊寬度</span>
顯示效果圖以下:

用力圖簡介
有點有線,那末有關聯的點用線相連,再設置下點之間的電荷排擠力,讓沒關聯的點保持距離, 那末力圖的雛形就構成了。
力學圖( Force ),也有被翻譯做力導向圖等。這類圖很成心思,先從初始數據開始,看下面代碼:
{
"nodes":[
{"name":"Myriel","group":3,"QQ":"635511111"},
{"name":"Napoleon","group":1,"QQ":"635511112"},
{"name":"Mlle.Baptistine","group":1,"QQ":"635511113"},
{"name":"Mme.Magloire","group":1,"QQ":"635511114"},
{"name":"CountessdeLo","group":1,"QQ":"635511115"},
{"name":"Geborand","group":1,"QQ":"635511116"},
{"name":"Champtercier","group":1,"QQ":"635511117"},
{"name":"Cravatte","group":1,"QQ":"635512111"},
{"name":"Count","group":1,"QQ":"635513111"},
{"name":"OldMan","group":1,"QQ":"635514111"},
{"name":"Labarre","group":2,"QQ":"635515111"},
{"name":"Valjean","group":2,"QQ":"635516111"},
{"name":"Marguerite","group":3,"QQ":"635531111"},
{"name":"Mme.deR","group":2,"QQ":"635511311"},
{"name":"Isabeau","group":2,"QQ":"635511211"},
{"name":"Gervais","group":2,"QQ":"635514111"},
{"name":"Tholomyes","group":3,"QQ":"635571111"},
{"name":"Listolier","group":3,"QQ":"635581111"},
{"name":"Fameuil","group":3,"QQ":"635511011"},
{"name":"Blacheville","group":3,"QQ":"635211111"},
{"name":"Favourite","group":3,"QQ":"635510111"},
{"name":"Dahlia","group":3,"QQ":"635511121"}
],
"links":[
{"source":1,"target":0,"value":1},
{"source":2,"target":0,"value":8},
{"source":3,"target":0,"value":10},
{"source":3,"target":2,"value":6},
{"source":4,"target":0,"value":1},
{"source":5,"target":0,"value":1},
{"source":6,"target":0,"value":1},
{"source":7,"target":0,"value":1},
{"source":8,"target":0,"value":2},
{"source":9,"target":0,"value":1},
{"source":11,"target":1,"value":1},
{"source":11,"target":3,"value":3},
{"source":11,"target":2,"value":3},
{"source":11,"target":0,"value":5},
{"source":12,"target":2,"value":1},
{"source":13,"target":2,"value":1},
{"source":14,"target":2,"value":1},
{"source":15,"target":2,"value":1},
{"source":17,"target":3,"value":4},
{"source":18,"target":3,"value":4},
{"source":18,"target":3,"value":4},
{"source":19,"target":3,"value":4},
{"source":19,"target":2,"value":4},
{"source":19,"target":3,"value":4},
{"source":20,"target":4,"value":3},
{"source":20,"target":1,"value":3},
{"source":20,"target":2,"value":3},
{"source":20,"target":3,"value":4},
{"source":21,"target":16,"value":3},
{"source":21,"target":17,"value":3},
{"source":21,"target":18,"value":3},
{"source":21,"target":19,"value":3},
{"source":21,"target":20,"value":5}
]
}
這些數據包括兩部份,點(nodes)和邊(links),source 和target的數值代表nodes數組該數值下標對應的元素。
注意的1點,不管nodes元素有多少屬性,source和target都暫時指向人名,如source 1 target0 表示napoleon和myriel連接
細細1看就會發現,這些點只是些人員的屬性而已,光靠這些是沒法知道每一個點該畫到哪兒。
所以就需要先了解1下D3 畫力圖的1些專有方法了 。下面為大家羅列1些必要的方法和解釋:
為了使用方便先將上面的json數據,賦值給 dataset,放到js里
(以后這些數據都會保存在相應格式的文件中,由d3加載,加載方法在 D3整體展現篇已略有介紹)
var force = d3.layout.force() //轉換數據的方法,將點轉換為坐標格式
.nodes(<span style="font-size:14px;">dataset.</span>nodes) //傳入點
.links(dataset.links) //傳入邊
.size([w, h]) //設置圖形寬高
.start(); //開始轉換
以上代碼是 用力圖最基礎的布局方法。
這些基本布局其實不能滿足所有數據集,我們還要在這基礎上添加1些layout的自定義方法,
比如設置節點間連線的長度、節點間互斥力大小。完善以后的代碼顯示以下:
var force = d3.layout.force()
.nodes(dataset.nodes)
.links(dataset.edges)
.size([w, h])
.linkDistance([50]) // 節點連線長度
.charge([⑴00]) // 排擠力
.start();
至此,力圖基本初始化布局完成
接下來創建連線
var edges = svg.selectAll("line")
.data(dataset.edges)
.enter()
.append("line")
.style("stroke", "#ccc")
.style("stroke-width", 1);
這里的連線色彩和寬度都可以編寫函數隨便設定,例猶如類人員設為同色,重要人員連線加粗等
然后為每一個節點創建圓,方便閱讀
var nodes = svg.selectAll("circle")
.data(dataset.nodes)
.enter()
.append("circle")
.attr("r", 10)
.style("fill", function(d, i) {
return colors(i);
})
.call(force.drag); //增加拖動效果,拉動節點
最后,我們就要打點,將點線繪制到畫布上
force.on("tick", function() {
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; });
nodes.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
這樣,每次打點,獲得線和點的坐標,在更新到畫布上。那末這些坐標哪兒來的?就是layout初始化轉換傳入的點線數據后,
為他們摹擬1些坐標信息。你可以在閱讀器控制臺輸入dataset查看各點線坐標信息

好了,最簡單的用力圖就這樣完成了,后文會繼續在此基礎上講授如作甚個點設置圖標、如何實現不同分組的群成員聚類縮放、如何顯示成員信息、如何將圓替換為矩形塊放置屬性聯系方式等,敬請期待!
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈