首先我們先來解釋下arc生成器與chord生成器,其實所謂的生成器其實都是路徑生成器的一種,在svg中有個標籤元素,<path d=”“> </path>,我們發現有個d屬性需要我們填寫,我們當然可以自己填寫,比如M0,0L1,1L2,2這些,但是這只是線段,如果弧,弦這種呢?根本就沒法寫,況且就算由點連成的線段寫起來也很麻煩,與是d3給我們寫了一個這樣一系列函數,用來專門生成我們想要的圖形路徑字符串,這樣很方便了有沒有呢!!
路徑生成器的種類有:line,arc,chord,area,diagonal,用法都很類似,學會了一個那麼其他就很容易接受了。我們這一次主要講arc,與chord
- [ ] arc生成器
先看下代碼,試着理解下
/*弧生成器 生成扇形一般用法*/
var width=200,height=200;
var data = [
{startAngle:0,endAngle:2*Math.PI/3},
{startAngle:2*Math.PI/3,endAngle:4*Math.PI/3},
{startAngle:4*Math.PI/3,endAngle:2*Math.PI}
];
//arc生成器對象
var arc = d3.svg.arc()
.innerRadius(0) //定義內徑
.outerRadius(90)//定義外徑
//svg容器
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height);
//顏色比例尺
var color=d3.scale.category10();
//把path放到容器中,並給d賦屬性
var arcGraph = svg.selectAll("g .arc")
.data(data)
.enter()
.append("g")
.attr("class","arc")
.append("path")
.attr("d",function(d){
return arc(d); //arc對象包裹數據進去
})
.attr("stroke","white")
.attr("stroke-width",2)
.attr("fill",function(d,i){
return color(i);
})
.attr("transform","translate(100,100)");
svg.append("g")
.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("transform",function(d){
return "translate("+width/2+","+height/2+")"+
"translate("+arc.centroid(d)+")"; //取得arc路徑的圓心
})
.attr("text-anchor","middle")
.attr("fill","black")
.attr("font-size",12)
.text(function(d){
return parseInt((d.endAngle-d.startAngle)*180/Math.PI+"'");
})
其實我們也可以在定義arc的時候就將所有參數定義好,如下:
var arc = d3.svg.arc()
.innerRadius(0) //定義內徑
.outerRadius(90)//定義外徑
.startAngle() //角度是以0點爲起始點,弧度爲單位
.endAngle()
只不過這樣定義就會不靈活,只能生成一個弧,所有的參數沒法改變,如果作爲數據綁定給path元素,將starAngel與endAngle動態傳進去,那麼久可以一次生成好多弧。總之最後d的參數,一定是所有的數據都要擁有, ,一般是第一種更多,更靈活。
- [ ] chord生成器
還是先看下代碼,試着理解編寫者的用意
/*chord生成器*/
var width=400,height=400;
//一個chord必須要source與target 成對出現,一個source,一個target分別是一個弧,兩個弧連線正好就是兩條弦,所謂的chord生成器
var data = [
{
source:{startAngle:2*Math.PI/3,endAngle:4*Math.PI/3,radius:90},
target:{startAngle:5*Math.PI/3,endAngle:6*Math.PI/3,radius:90}
},
{
source:{startAngle:0,endAngle:1*Math.PI/3,radius:80},
target:{startAngle:4*Math.PI/3,endAngle:5*Math.PI/3,radius:80}
},
];
var chord = d3.svg.chord();
//svg容器
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height);
var color=d3.scale.category10();
//把path扔到容器中,並給d賦屬性
var arcGraph = svg.selectAll("g .arc")
.data(data)
.enter()
.append("g")
.append("path")
.attr("d",chord) //綁定chord對象
.attr("stroke","black")
.attr("stroke-width",2)
.attr("fill",function(d,i){
return color(i);
})
.attr("transform","translate(100,100)");
- [ ] 佈局講解
下面我們來看下chord佈局,佈局就是d3爲我們寫好的某個具體樣式,其他還有如pie,chord,等,這些都是佈局,將佈局與路徑生成器結合起來用,會更方便快捷。
爲了方便理解佈局的共同特性,我們先來看下pie佈局,最簡單的這個
<style type="text/css">
text {
font-family: sans-serif;
font-size: 12px;
fill: white;
}
</style>
<body>
</body>
<script type="text/javascript">
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var w=300;
var h=300;
var outerRadius=w/2;
var innerRadius=w/3;
/* arc路徑生成器設定半徑*/
var arc=d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
/*定義一個pie*/
var pie=d3.layout.pie();
var color=d3.scale.category10();
var svg=d3.select("body")
.append("svg")
.attr("width",w)
.attr("height",h)
/*開始對每個扇形(startAngle,endAngle,value)進行綁定,放在透明g元素中*/
var arcs=svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class","arc")
.attr("transform","translate("+w/2+","+w/2+")")//放到svg中心
/*爲每個g以弧參數生成路徑*/
/*d當用佈局的時候,就不需要再用路徑生成器包裹數據了*/
arcs.append("path")
.attr("fill",function(d,i){
return color(i);
})
.attr("d",arc);
arcs.append("text")
.attr("transform",function(d){
return "translate("+arc.centroid(d)+")";
})
.attr("text-anchor","middle")
.text(function(d){
return d.value;
})
</script>
當我們console.log(pie(dataset))的結果,pie(data)爲我們將數據,根據佔比生成了所有arc需要的路徑數據,結果如下圖
總結成一句話就是,用佈局包裹數據,會生成這個佈局所需要的特定數據
最後,我們來看以arc生成器與chord生成器爲前提的chord佈局的使用
還是先看代碼
<script type="text/javascript">
//註釋掉的是數據樣例,直觀理解數據組成
/*數據說明:矩陣的值表示每個維度的相關性,如通信多少次,或者每個row由多少個coloumn組成*/
// var city_name = [ "北京" , "上海" , "廣州" , "深圳" , "香港" ];
// var population = [
// 北京 上海
// 北京[ 3214, 2000 , 2060 , 124 , 3234 ],
// [ 8761, 6545 , 3000 , 8045 , 647 ],
// [ 3211, 1067 , 3214 , 4000 , 1006 ],
// [ 2146, 1034 , 6745 , 4764 , 5000 ]
// ];
/*chord上的數字,比如說2000,代表了北京人口中,上海人口占2000*/
//生成一個數據矩陣
var matrix=new Array(15);
for (var i=0;i<15;i++){
matrix[i] = new Array(15)
for (var j=0;j<15;j++){
matrix[i][j]=parseInt(Math.random()*8);
}
}
/*定義一個弦佈局*/
console.log(matrix)
var chord_layout=d3.layout.chord()
.padding(0.05) //弧間距
.sortSubgroups(d3.ascending()) //結點排序方式
.matrix(matrix); //加載數據
/*拿到弧跟節點*/
//弦佈局整合後的數據,一個是groups弧節點,四個字段:index,startangle(弧度爲單位),endangle,value一個是弦數據,source與target,每個字段中又有index,subindex,startangle,endangle,value;
var groups=chord_layout.groups(); //包裹了arc數據
var chords=chord_layout.chords(); //包裹了chord數據
//可以在控制檯看下
console.log(groups)
console.log(chords)
/*svg畫布*/
var width=500,height=400;
var svg=d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height)
.append("g")
.attr("transform","translate("+width/2+","+height/2+")")
/*用弧生成器*/
var innerRadius=height/3.5,outerRadius=height/3;
var arc=d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var color=d3.scale.category20();
var g_outer=svg.append("g")
/*弧節點路徑*/
g_outer.selectAll("path.arc")
.data(groups) //包裹所需數據
.enter()
.append("path")
.attr("class","arc")
.attr("d",arc) //引用生成器
.attr("fill",function(d,i){
return color(d.index);
})
.attr("stroke",function(d,i){
return color(d.index);
})
/*弧外邊文字*/
g_outer.selectAll("text .arc")
.data(groups)
.enter()
.append("text")
.attr("class","arc")
.each(function(d,i){
d.angle=(d.startAngle+d.endAngle)/2;
d.name=i;
})
.attr("transform",function(d,i){
return "rotate(" + ( d.angle * 180 / Math.PI ) + ")" +
"translate(0,"+ -1.0*(outerRadius+10) +")" +
( ( d.angle > Math.PI*3/4 && d.angle < Math.PI*5/4 ) ? "rotate(180)" : "");
})
.attr("dy",".35em")
.attr("text-anchor","middle")
.text(function(d,i){
return d.name;
})
//內chord生成
var inner_chord=d3.svg.chord()
.radius(innerRadius)
svg.append("g")
.selectAll("path .chord")
.data(chords) //綁定所需數據
.enter()
.append("path")
.attr("class","chord")
.attr("d",inner_chord) //引用生成器
.attr("opacity",0.7)
.attr("fill",function(d,i){
return color(d.source.index)
})
.on("mouseover",function(d,i){ //事件響應
d3.select(this)
.attr("fill",function(d,i){
return "black";
})
})
.on("mouseout",function(d,i){
d3.select(this)
.transition()
. duration(1000)
.attr("fill",function(d,i){
return color(d.source.index);
})
})
.append("title")
.text(function(d) {
return "This value is " + d.target.value;
});
</script>
上邊的代碼告訴我們,一個chord佈局爲我們生成所需要的弧數據與弦數據,我們只需要引用各自的生成器就行了。
我們看下在代碼中的兩個控制檯輸出的數據
groups變量
chord變量
最後這個是最後生成的圖