D3(Data-Driven Documents)学习
被数据驱动的文档,其实就是一个JavaScript函数库,主要用来做数据可视化。
一.
1.选择集
-
d3.select():选择所有指定元素的第一个
-
d3.selectAll():选择指定全部元素
<p class="myclass">Sun</p> <p id="moon">Moon</p> <p class="myclass">You</p> //选择第一个元素 d3.select("body").select("p").style("color","red"); //选择所有元素 d3.select("body").selectAll("p").style("color","red"); //选择第二个元素 d3.select("#moon").style("color","red"); //选择另外两个元素 d3.selectAll(".myclass").style("color","red");
2.绑定数据
-
datum():绑定一个数据到选择集上
-
data():绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定
3.插入元素
-
append():在选择集末尾插入元素
-
insert():在选择集前面插入元素
d3.select("body").append("p").text("Star");//在所有p前加入Star字段 d3.select("body").insert("p","#moon").text("Star");//在id为moon前加入Star字段
4.删除元素
-
remove():删除元素
d3.select("#moon").remove
二.做一个简单的图表
-
SVG绘制的是矢量图,对图像进行放大不会失真,每个图像均视为对象,在SVG中,x轴的正方向是水平向右,y轴的正方向是垂直向下的。
-
canvas中,一旦图形被绘制完成,如果位置发生变化,整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。
-
使用D3在body元素中添加svg:
添加画布
var width = 300;//画布宽度 var height = 300;//画布高度 var svg = d3.select("body") //选择文档中的body元素 .append("svg") //添加一个svg元素 .attr("width",width) //设定宽度 .attr("height",height); //设定高度
绘制矩形
绘制一个横向的柱形图,只绘制矩形,不绘制文字和坐标轴,矩形的元素标签是rect
<svg> <rect></rect> <rect></rect> </svg>
矩形的属性:
x:矩形左上角的x坐标 y:矩形左上角的y坐标 width:矩形的宽度 height:矩形的高度
给出一组数据,进行可视化
//横向 var dataset = [250,210,170,130,90]; //数据(表示矩形的宽度) var width = 300;//画布的宽度 var height = 300;//画布的高度 var svg = d3.select("body") .append("svg") .attr("width",width) .attr("height",height) var rectHeight = 25; //每个矩形所占的像素高度 svg.selectAll("rect") .data(dataset) .enter() .append("rect") .attr("x",20) .attr("y",function(d,i){ return i*rectHeight; }) .attr("width",function(d){ return d; }) .attr("height",rectHeight-2) .attr("fill","steelblue"); //纵向 svg.selectAll("rect") .data(dataset) .enter() .append("rect") .attr("x",function(d,i){ return i*rectHeight }) .attr("y",function(d,i){ return height-d; }) .attr("height",function(d){ return d; }) .attr("width",rectHeight-2) .attr("fill","steeblue");
三.比例尺
-
线性比例尺(能将一个连续的区间,映射到另一区间)
var dataset = [1.2,2.3,0.9,1.5,3.3] //将dataset中最小的值映射成0,最大的值映射成300 var min = d3.min(dataset); var max = d3.max(dataset); var linear = d3.scale.linear() //线性比例尺 .domain([min,max])//定义域 .range([0,300]);//值域 linear(0.9); //返回0 linear(2.3);//返回175 linear(3.3);//返回300
-
序数比例尺(有时候定义域和值域不一定是连续的)
var index = [0,1,2,3,4]; var color = ["red","blue","green","yellow","black"]; //希望0对应red,以此类推 var ordinal = d3.scale.ordinal() .domain(index) .range(color); ordinal(0);//返回red ordinal(1);//返回blue
-
给柱形图添加比例尺
var dataset=[2.5,2.1,1.7,1.3,0.9]; var linear = d3.scale.linear() .domain([0,d3.max(dataset)])//定义域 .range([0,250]);//值域 var rectHeight = 25; //每个矩形所占的像素高度 svg.selectAll("rect") .data(dataset) .enter() .append("rect") .attr("x",20) .attr("y",function(d,i){ return i*rectHeight; }) .attr("width",function(d){ return linear(d); //这里使用比例尺 }) .attr("height",rectHeight-2) .attr("fill","steelblue");
四.坐标轴
坐标轴由一些列线段和刻度组成,坐标轴在SVG中是没有现成的图形元素的,需要用其他的元素组合构成,D3提供了坐标轴的组件,使在SVG中绘制坐标轴变得像添加一个普通元素一样简单。
定义坐标轴
var dataset = [2.5,2.1,1.7,1.3,0.9];
//定义比例尺
var linear = d3.scale.linear()
.domain([0,d3.max(dataset)])
.range([0,250]);
var axis = d3.svg.axis()//坐标轴组件
.scale(linear) //指定比例尺
.orient("bottom") //指定刻度的方向
.ticks(7); //指定刻度的数量
在SVG中添加坐标轴
svg.append("g").call(axis);
设定坐标轴的样式和位置
//下列是一个常用的样式
<style>
.axis path,
.axis line{
fill: none;
stroke:black;
shape-rendering:crispEdges;
}
.axis text{
font-family:sans-serif;
font-size:11px;
}
</style>
//将坐标轴的类设定为axis,坐标轴的位置通过transform来设定
svg.append("g")
.attr("class","axis")
.attr("transform","translate(20,130)")
.call(axis)//改变this指向,指向axis
五.完整的柱形图
制作一个完整的柱形图,包括矩形,文字,坐标轴(内容包括:选择集,数据绑定,比例尺,坐标轴)
添加SVG画布
//画布大小
var width = 400;
var height = 400;
//在body里添加一个svg画布
var svg = d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);
//画布周围的空白
var padding = {left:30,right:30,top:20,bottom:20};
定义数据和比例尺
//定义一个数组
var dataset = [10,20,30,40,33,24,12,5];
//x轴的比例尺
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0,width-padding.left-padding.right]);
//y轴的比例尺
var yScale = d3.scale.linear()
.domain([0,d3.max(dataset)])
.range([height-padding.top-padding.bottom,0]);
定义坐标轴
//定义x轴
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
//定义y轴
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
添加矩形和文字
//矩形之间的空白
var rectPadding = 4;
//添加矩形元素
var rects = svg.selectAll(".MyRect")
.data(dataset)
.enter()
.append("rect")
.attr("class","MyRect")
.attr("transform","translate("+padding.left+","+padding.top+")")
.attr("x",function(d,i){
return xScale(i)+rectPadding/2
})
.attr("y",function(d){
return yScale(d);
})
.attr("width", xScale.rangeBand() - rectPadding )
.attr("height", function(d){
return height - padding.top - padding.bottom - yScale(d);
})
.attr("fill","steelblue");
//添加文字元素
//添加文字元素
var texts = svg.selectAll(".MyText")
.data(dataset)
.enter()
.append("text")
.attr("class","MyText")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("x", function(d,i){
return xScale(i) + rectPadding/2;
} )
.attr("y",function(d){
return yScale(d);
})
.attr("dx",function(){
return (xScale.rangeBand() - rectPadding)/2;
})
.attr("dy",function(d){
return 20;
})
.text(function(d){
return d;
})
.style({
"fill":"#FFF",
"text-anchor":"middle"
});
添加坐标轴元素
//添加x轴
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
.call(xAxis);
//添加y轴
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.call(yAxis);
六.动态图表
- transition()启动过渡效果
.attr("fill","red")//初始颜色为红色
.transition() //启动过渡
.attr("fill","steelblue")//终止颜色为铁蓝色
-
duration()指定过渡的持续时间,单位为毫秒。如duration(2000),指持续2000毫秒,即2秒。
-
ease()指定过渡的方式,常用的有:
linear:普通的线性变化
circle:慢慢地达到变换的最终状态
elastic:带有弹跳的到达最终状态
bounce:在最终状态处弹跳几次
调用时格式如:ease(“bounce”)
-
delay()指定延迟的时间,表示一定时间后才开始转变,此函数可以对整体指定延迟,也可以对个别指定延迟
//整体指定 .transition() .duration(1000) .delay(500) //个别指定 .transition() .duration(1000) .delay(function(d,i){ return 200*i; })
一些动画效果
var circle1 = svg.append("circle")
.attr("cx",100)
.attr("cy",100)
.attr("r",45)
.style("fill","green");
circle1.transition()
.duration(1500)
.attr("cx",300) //移动x轴
.style("fill","red")//改变圆颜色
.attr("r",25)//改变半径
七.理解update(),enter(),exit()
处理当选择集和数据的数量关系不确定的情况。
- update():当对应的元素正好满足时(绑定数据量 = 对应元素),实际上并不存在这样的一个函数,只是为了要与之后的enter和exit一起说明才想象有这样一个函数。但对应元素正好满足时,直接操作即可,后面直接跟text,style等操作即可。
- enter():当对应的元素不足时(绑定数据量>对应元素),通常要添加元素,使之与绑定数据的数量相等。后面通常先跟append操作。
- exit():当对应元素过多时(绑定数据量<对应元素),通常要删除元素,使之与绑定数据的数量相等。后面通常要跟remove操作。
八.交互式操作
与图表的交互,指在图形元素上设置一个或多个监听器,当事件发生时,作出相应的反应。
添加交互
var circle = svg.append("circle");
circle.on("click",function(){ //通过on添加了一个监听器
//在这里添加交互内容
})
鼠标事件
- click:鼠标单击某元素时,相当于mousedown和mouseup组合在一起
- mouseover:光标放在某元素上
- mouseout:光标从某元素上移出来
- mousemove:鼠标被移动的时候
- mousedown:鼠标按钮被按下
- mouseup:鼠标按钮被松开
- dblclick:鼠标双击
键盘事件
- keydown:当用户按下任意键时触发,按住不放会重复触发此事件。该事件不会区分字母的大小,例如A和a被视为一致。
- keypress:当用户按下字符键(大小写字母,数字,加号,等号,回车等)时触发,按住不放会重复触发此事件。该事件分字母大小写。
- keyup:当用户释放键时触发,不区分大小写。
九.布局
layout,作用时:将不适合用于绘图等数据转换成了适合用于绘图的数据,可以理解成数据转化。
D3提供了12个布局:饼状图(Pie),力导向图(Force),弦图(Chord),树状图(Tree),集群图(Cluster),捆图(Bundle),打包图(Pack),直方图(Histogram),分区图(Partition),堆栈图(Stack),矩阵树图(Treemap),层级图(Hierarchy),其中层级图不能直接使用。集群图,打包图,分区图,树状图,矩阵树图是由层级图扩展来的。
十.绘制饼状图
var dataset = [30,10,43,55,13];
//定义一个布局
var piedata = pie(dataset);
//绘制图形
var outerRadius = 150;//外半径
var innerRadius = 100;//内半径,为0则中间没有空白
var arc = d3.svg.arc;//弧生成器
.innerRadius(innerRadius) //设置内半径
.outerRadius(outerRadius) //设置外半径
var arcs = svg.selectAll("g")
.data(piedata)
.enter()
.append("g")
.attr("transform","translate("+ (width/2) +","+ (width/2) +")");
arcs.append("path")
.attr("fill",function(d,i){
return color(i);
})
.attr("d",function(d){
return arc(d);//调用弧生成器,得到路径值
})
//在每一个弧线中心添加文本
arcs.append("text")
.attr("transform",function(d){
return "translate(" + arc.centroid(d) + ")"; //arc.centroid(d)能算出弧线的中心
})
.attr("text-anchor","middle")
.text(function(d){
return d.data;
});