陈建华的博客
专注web开发
D3.js面积(area)图与缩放查看(序4)
2014-09-16 17:38:44   阅读1993次

这一次我们要做一个实用性比较强的图表:带缩略图拖拽查看的面积图。

面积图强调数量随时间而变化的程度,是非常常用的可视化图表

最终demo  http://www.d3js.cn/demo/brush.html

本次的demo  http://www.d3js.cn/demo/brush2.html

 

首先我们观察下效果图

 wwwq.jpg

上面的效果图是由两个面积图组成的。我们首先要绘制出这两个静态的图表,然后根据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



-----------------------------------------------------
转载请注明来源此处
原地址:#

-----网友评论----
暂无评论
-----发表评论----
微网聚博客乐园 ©2014 blog.mn886.net 鲁ICP备14012923号   网站导航