D3学习备忘

前言

在web前端开发中,时常会碰到显示图表的需求。而在这个领域中,国内最有名的库莫过于Echarts了,其他的还有Antg2highchartchart.js等,这些库的特点是开箱即用,基于配置,根据官方提供的demo,进行一定的调整就能够满足开发的任务的,也有提供自定义的方案,满足特殊的需求。

不过我总感觉不能满足于这种高级封装库提供的便利,因为这样比较难提升自己的开发能力,所以希望去折腾些较底层的库,让自己可以多动些脑筋。(也有一种潮流是直接使用React这类前端框架,做可视化的工作(同样也是数据驱动视图),不过这样子就相当于再造一个轮子了)

d3就是一个很好的选择,历史悠久,使用者众多,作者Mike Bostock也是个很有创造力的开发者,独力写了很多优秀的可视化demo,除了d3还创建了可视化分享平台Observerblehq

API设计方面采用了类似JQuery的链式调用,代码组织的特点是分成了多个独立的模块,分开仓库进行管理,所以也方便使用者按需引入。d3的类的创建,不使用new的方式,而通过函数返回一个新的对象,对象相关的变量,存储在闭包内。

我觉得d3主要是一个可视化数据处理工具函数的库,不提供图形渲染引擎,所以可以让使用者全盘掌控显示的内容。

API概念说明

d3.selection

d3的DOM操作的风格十分类似Jquery

  1. 创建DOM元素并返回一个类似Jquery集合的Selection对象
1
d3.create('svg')
  1. 选择DOM元素,selectselectAll都会返回一个Selection

    1
    2
    3
    4
    5
    selection.select('rect')
    selection.selectAll('rect')
    // 或者使用d3的静态方法
    d3.select('rect')
    d3.selectAll('rect')
  2. 绑定数据。绑定数据的方法有datadatum两种,data会返回一个新的集合并逐一把每一行数据绑定给selection中的成员,如原selection中的成员数量比data的行数小,则新创建的selection会使用占位用的empty补足;datum则是将整组数据逐一绑定给每一个selection成员,不会产生新的集合。

    1
    2
    3
    4
    let arr: any[]
    selection.data(arr)
    // 设置selection各成员绑定的数据
    selection.datum(arr)
  3. 绑定数据的行数与selection的数量有出入时,d3会产生enterexit的集合。但是并不会默认给enter的集合自动创建对应的DOM元素,这时可使用join去创建。

1
2
3
4
let arr: any[]
selection.data(arr).join('rect'/** 元素的标签名 */)
// 与上面等价
selection.data(arr).enter().append('rect')
  1. selection.call接收一个以selection为参数的回调函数,目前看来用途主要给selection添加一些子元素,这样就不会改变外部链式调用的主体。
1
selection.call((s) => s.append('path'))
  1. selection.each方法并不会回传一个子selection,而是回传三个参数d子data), i(索引),nodesGroupselection内部的DOM集合),回调函数的this等同于nodesGroup[i]
    1
    2
    3
    4
    selection.each(function (d, i, nodesGroup) {
    // 由于并不是子selection,所以需要进行select把DOM变成d3的selection对象
    d3.select(this)
    })

d3.Shape

  1. d3.lineRadiald3.line作用同样都是生成线段,不同的是lineRadial的坐标系是极坐标系,而且需要注意的是0 rad12点方向,角度增长为顺时针,每个点由angleradius方法定义。

d3.polygon

  1. d3.polygonCentroid,求多边形的中点a。

原理是以[P_(n - 1), P_n, [0, 0]]为顶点组成三角形,求出各个三角形的中点P_m_n(顶点坐标和除以3)。

然后各个顶点根据权重W(三角形n的面积 / 所有三角形的面积和)相加求得。

三角形的面积 = (V_(n - 1) X(叉积) V_n) * 0.5