这一次我们要做一个实用性比较强的图表:带缩略图拖拽查看的面积图。
面积图强调数量随时间而变化的程度,是非常常用的可视化图表
最终demo http://www.d3js.cn/demo/brush.html
本次的demo http://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年)
这一类的参数详解可以参考api https://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.把坐标轴插入到图表中
chart.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属性添加进去,就大功告成了。
本次的demo http://www.d3js.cn/demo/brush2.html
-----------------------------------------------------
转载请注明来源此处
原地址:#
发表