首先我们先来解释下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变量
最后这个是最后生成的图