Jade's fantastic Blog

Make a difference.Where amazing happens!

Thinking in D3

d3

前记

最近在使用D3做数据可视化开发,学到一些东西,因此写篇文章记录一下。

D3 是什么?

D3.js is a JavaScript library for manipulating documents based on data. D3.js 是一个基于数据,用于操纵文档的javascript库。

D3中含有3个D:Data, Driven, Documents。 通俗的讲,D3可以用来做一下事务:

  • 数据可视化
  • 数据交互
  • 数据实时更新

如果说大数据是一堆凌乱,毫无秩序的碎片, 那么D3就是可以让这些凌乱不堪的数据变得井然有序的指挥手。

为什么选择D3?

  • 开源,并且在github中获得star前10位 (BSD licensed (BSD-new))
  • jQuery相似的API
  • 背后有商业公司支持(New York Times)
  • 社区活跃, 问题可以得到及时的解答, 以下是D3在Github中的实时状态
    D3-status
  • 方便扩展和调试,可以对Dom直接操作
  • 简单,快速,高效
  • 完美的动画支持

在对比了无数可视化library,发现D3能够满足目前项目的需求,于是果断使用。当然,如果你的银子不在乎, 可以考虑使用highchart, 目前被很多大公司使用, 非常稳定。

使用起来方便吗?

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 定义边距值
var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
    
var parseDate = d3.time.format("%d-%b-%y").parse;

// 定义x坐标的值类型和范围
var x = d3.time.scale()
    .range([0, width]);
    
// 定义y坐标的类型和使用范围
var y = d3.scale.linear()
    .range([height, 0]);

// 定义x轴的样式以及数据源
var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");
    
// 定义y轴的样式和数据源
var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

// 定义线段的取值范围
var line = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.close); });

// 向Dom body元素中加入一个svg元素并指定svg的大小
var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// 加载数据源
d3.tsv("data.tsv", function(error, data) {
  
  // 数据预处理
  data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.close = +d.close;
  });
  
  //定义x,y坐标领域值范围
  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain(d3.extent(data, function(d) { return d.close; }));
  
  //添加g元素用于组合x,y轴(svg中部分元素必须置于g中才能正常显示)
  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
  
  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("Price ($)");
  
  // 创建线段
  svg.append("path")
      .datum(data)
      .attr("class", "line")
      .attr("d", line);
});

上面的代码是不是很容易懂? 如果你对SVG概念有个大概的了解, 并且会使用jQuery, 那么你会很容易上手。

如何开始学习使用?

  • 首先,你需要对SVG有足够的了解和认识
  • 然后,学习D3基本语法规则
  • 查看example, 实践
  • 优化, 实践…

简单解析D3源码

为什么要看源码?我的想法是,知其然还不够,知其所以然可以让我们更快更好的发现问题并解决。同时可以让我们学习到不同的方法来创建,管理一个framework。

  • 文件结构
    • bin 基础性的配置工具,bower, uglyfy等
    • lib 第三方的库以及版权信息
    • src 所有D3领域编程源码,在所有的源码中,每个目录都会有一个index.js文件,用来定义所有在当前目录中的模块以及以来顺序
    • test 所有的单元测试文件
  • 开发流程(根据文件结构及构建脚本推断)
    1. 首先定义好所有领域原子模块,如: svg, xhr, event, color, geo等
    2. 对于每个原子模块在进行细分,如: svg中的线段,圆弧等基本图标属性
    3. 定义index.js来包含原子模块,并定义依赖关系
    4. 使用Make脚本测试,打包生成生产环境可以使用的代码
    5. 部署到travis CI server进行集成测试
  • 工具使用
    • smash 根据index.js中定义的规则合并原子模块
    • Uglyfy 用于minify JS
    • vows 用于单元测试
    • jsdom在node环境中模拟Dom tree 在看了一些D3的源码之后,我的感觉是非常的简洁,模块化,非常值得借鉴,如果你有想法要构建一个XXX library的时候,不妨参考一些D3的源码。欣赏一下D3的构建脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
GENERATED_FILES = \
  d3.js \
  d3.min.js \
  bower.json \
  component.json

all: $(GENERATED_FILES)

.PHONY: clean all test

test:
  @npm test

src/start.js: package.json bin/start
  bin/start > $@

d3.js: $(shell node_modules/.bin/smash --ignore-missing --list src/d3.js) package.json
  @rm -f $@
  node_modules/.bin/smash src/d3.js | node_modules/.bin/uglifyjs - -b indent-level=2 -o $@
  @chmod a-w $@

d3.min.js: d3.js bin/uglify
  @rm -f $@
  bin/uglify $< > $@

%.json: bin/% package.json
  @rm -f $@
  bin/$* > $@
  @chmod a-w $@

clean:
  rm -f -- $(GENERATED_FILES)

虽然目前前端开发有比较成熟的Grunt, 但是在某些场景下有点过于繁琐和笨重, 这时候使用Make file会是比较好的选择。

学习资料

结论

D3的使用是非常优雅, 但是学习曲线非常陡峭,有很多领域知识需要学习,如果不想学习D3, 但又想快速使用D3来构建分析图表,那么可以考虑使用 NVD3 或者 D4。同时,众所周知SVG不支持<=IE8, 那么在IE8中可以使用:

  • aight 让D3可以在IE8中工作
  • R2D3 同时使用Raphael和D3
  • 通过特性检测选择使用不同的library document.implementation.hasFeature ("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1");

对于性能方面,如果页面节点过多,还是考虑使用canvas。另外,为了更好的使用D3,可以试用D3的领域知识加上AngularJS创建custom的component, 这样在未来的开发中可以加快开发进度, 并且拥抱web component。

Comments