这一次我们要做一个实用性比较强的图表:带缩略图拖拽查看的面积图。
面积图强调数量随时间而变化的程度,是非常常用的可视化图表
最终demohttp://www.d3js.cn/demo/brush.html
本次的demohttp://www.d3js.cn/demo/brush2.html
首先我们观察下效果图
上面的效果图是由两个面积图组成的。我们首先要绘制出这两个静态的图表,然后根据d3js提供的强大工具来制作缩略拖拽查看的效果.
首先定义好图表尺寸
var margin = {top: 10, right: 10, bottom: 100, left: 40},
//上图位置
margin2
= {top: 430, right: 10, bottom: 20, left:
40},//下图位置
width
= 960 - margin.left - margin.right,//总宽
height
= 500 - margin.top - margin.bottom,//总高
height2
= 500 - margin2.top - margin2.bottom;//下图宽度
之后我们建立一个工具函数,来格式化时间
var parseDate = d3.time.format("%b %Y").parse;
//format
d3.time.format方法是非常有用的一个函数。可以通过设置一定的传入格式来格式化时间。注意,若要返回转换后的时间对象,需要使用parse函数。
此处%b表示月份的缩写,%Y表示一个带有世纪的年份 (比如2012年,而不是12年)
这一类的参数详解可以参考apihttps://github.com/mbostock/d3/wiki/Time-Formatting
比如我的原始数据源是Jan 2000
可以使用
d3.time.format("%b %Y").parse('Jan 2000')
来得到时间对象.那么这个时间对象是啥呢,他是javascript标准的时间对象。通过这个对象,可以非常方便的取得各种想要的时间单位。
比如
d3.time.format("%b %Y").parse('Jan
2000').getFullYear()//返回2000
具体可以参考http://www.w3cschool.cn/jsref_obj_date.html
之后因为出现了坐标轴,我们需要绘制坐标轴。绘制坐标轴需要使用axis系列api。大家可以复习下第三篇
axis
http://www.civn.cn/p/12474.html注意绘制坐标轴的步骤一定要掌握
1.规定数据范围
利用x.scale.linear之类api配合range
2.构造坐标轴
var xAxis = d3.svg.axis()
.scale(数据范围)
.orient(排列方式)
3.把坐标轴插入到图表中
图表.append("g")
.attr("class",
"坐标轴class")
.call(坐标轴);
遵循以上的步骤,就可以轻松绘制坐标轴了。
var x = d3.time.scale().range([0, width]), //建立数据容器
把数值转为时间标度再转为宽度
x2
= d3.time.scale().range([0, width]),
y
= d3.scale.linear().range([height, 0]),//直线标度 Learning
D3.js(1)学习制作一个柱形图/直方图
y2
= d3.scale.linear().range([height2, 0]);
var xAxis =
d3.svg.axis().scale(x).orient("bottom"),//制作上图的X轴
xAxis2
=
d3.svg.axis().scale(x2).orient("bottom"),//制作下图的X轴
yAxis
= d3.svg.axis().scale(y).orient("left");//制作上图的Y轴
之后我们要开始绘制area(面积)了。上期教程大家应该已经明白chord的形状绘制也是通过path进行的。d3的area方法,同样返回的是path。大家可以复习下上期教程http://www.civn.cn/p/12629.html
area的api可以参考https://github.com/mbostock/d3/wiki/SVG-Shapes#wiki-area
官方推荐的一个一般写法
var x = d3.scale.linear().range([0, w]),
y
= d3.scale.linear().range([h, 0]);
var area = d3.svg.area()
.x(function(d)
{ return x(d.x); })
.y0(h)
.y1(function(d)
{ return y(d.y); });
x表示数据在横坐标的位置,y0可以认为是总高度,y1表示数据在纵坐标的高度
现在我们来生成这个area的path
var area = d3.svg.area()//生成上图area
注意这个area是一个path,要利用attr(d)加载进去
.x(function(d)
{ return x(d.date); })
.y0(height)
//https://github.com/mbostock/d3/wiki/SVG-Shapes#wiki-area
.y1(function(d)
{ return y(d.price); });
var area2 = d3.svg.area()//生成下图area
.x(function(d)
{ return x2(d.date); })
.y0(height2)
.y1(function(d)
{ return y2(d.price); });
之后给这两个area图造空间,扔进去。
var svg = d3.select("body").append("svg")//主容器
.attr("width",
width margin.left margin.right)
.attr("height",
height margin.top margin.bottom);
var focus = svg.append("g")//制作上图容器
.attr("transform",
"translate(" margin.left "," margin.top ")");
var context = svg.append("g")//制作下图容器
.attr("transform",
"translate(" margin2.left "," margin2.top ")");
注意属性设置的跟开始设置好的边距一致。
现在图表的结构基本制作好了。我们需要引入数据。数据文件:http://www.d3js.cn/demo/data.csv
D3js提供了非常多的方法来加载外部数据,这里我们使用d3.csv方法来加载数据
api可以参考https://github.com/mbostock/d3/wiki/CSV
这个方法会发起一个HTTP
GET请求,去请求指定的url下以逗号分隔的(CSV)文件。这个文件的内容被认为是符合RFC4180-compliant规范的。请求是异步处理的。当CSV数据有效后,会调用回调函数,传入数据作为参数。如果一个错误发生时,回调函数也会被调用,这时候可以在回调函数里捕获error。传入后的数据会调用d3.csv.parse函数。例如:
Year,Make,Model,Length
1997,Ford,E350,2.34
2000,Mercury,Cougar,2.38
解析后
[
{"Year": "1997", "Make":
"Ford", "Model": "E350", "Length": "2.34"},
{"Year": "2000", "Make":
"Mercury", "Model": "Cougar", "Length": "2.38"}
]
变为数组。因此我们可以利用foreach等方法来遍历之,也可以循环遍历
d3.csv("data.csv", function(error, data)
{//利用csv方法读取数据
data.forEach(function(d)
{//遍历数据
d.date
= parseDate(d.date);//读取date并转换为时间对象
d.price
= d.price;
});
x.domain(d3.extent(data.map(function(d)
{ return d.date; })));//利用domain方法给数据容器匹配上数据
y.domain([0,
d3.max(data.map(function(d) { return d.price;
}))]);
x2.domain(x.domain());
y2.domain(y.domain());
//添加上面图的图表
focus.append("path")
.datum(data)
.attr("d",
area);
//添加上面图的XY坐标轴
focus.append("g")
.attr("class",
"x axis")
.attr("transform",
"translate(0," height ")")
.call(xAxis);
focus.append("g")
.attr("class",
"y axis")
.call(yAxis);
//添加下面图的图表
context.append("path")
.datum(data)
.attr("d",
area2);
//添加下面图的X坐标轴
context.append("g")
.attr("class",
"x axis")
.attr("transform",
"translate(0," height2 ")")
.call(xAxis2);
});
之后我们利用call方法绑定两个坐标轴,再把两个绘制好的area利用attr的d属性添加进去,就大功告成了。
本次的demohttp://www.d3js.cn/demo/brush2.html
作者:新浪微博
Learning D3.js 系列
原文链接:http://www.civn.cn/p/13322.html