前文中已经提到,SVG从诞生之初起就可以非常方便地使用javascript脚本语言来进行其DOM对象的控制。当然,控制的方法有很多,有直接控制SVG对象的方法,例如使用原生js;有帮你封装一下图形接口再进行直接控制的js类库,如 Raphaël。但是正如我在第一篇文章中所说,d3作为一个中间型类库还能脱颖而出的重要原因,在于它突破了其他类库的那种直接控制表现层的机制,而采用了对于web图形处理领域较为新颖的数据驱动机制(2011),并获得了极大的成功。

数据驱动的历史

数据驱动编程并不是一个新鲜玩意,在老书《Unix编程艺术》中,作者在介绍Unix设计原则时,其中有一条为“表示原则:把知识叠入数据以求逻辑质朴而健壮”。其核心出发点是相对于程序逻辑,人类更擅长于处理数据。数据比程序逻辑更容易驾驭,所以我们应该尽可能的将设计的复杂度从程序代码转移至数据。这条原则早在70年代的软件危机中就得到了印证:凡是执着于逻辑实现的代码最终都难以维护,而将逻辑变化沉淀到数据集中的程序,则撑过了时间的检验。在web开发领域流行20多年的MVC架构,核心也是将数据、表现、操作分离从而降低程序复杂度。JAVA社区多年来就程序设计领域的讨论,翻来覆去也离不开数据驱动这个原则。

然而,web前端,尤其是图形图像处理领域,长期以来人们的关注点集中在图形渲染API,设计诸如var circle = paper.circle(50, 40 ,10)这样的图形呈现接口。对图形元素的使用,也长期停留在使用程序直接控制的状态。当然,如果交互逻辑少,即使图形略微复杂,这么做并非不可以。但是在创造交互逻辑复杂的数据可视化项目时,这种做法的代码复杂度会随着交互逻辑的规模指数上升,并带来许多意料之外的程序冲突——这一切与MVC之前的web开发领域或者70年代的软件危机原因如出一辙。有识之士很早就意料到这种问题,于是在web端图形处理的基础渲染技术已经渐渐完善的2011年,D3js诞生,并迅速在数据可视化领域和web图形渲染领域掀起了旋风。

对D3数据转换的理解

官网上的原文说,它注重的是是转化而不是表现(Transformation, not Representation)。d3不是一个新的图形呈现类库。不像 ProcessingRaphaël, 或者 Protovis这类类库,D3不注重对图形呈现接口的封装,而是使用web标准的HTML, SVG和CSS来处理表现层。这意味着如果哪一天浏览器支持了新的图形渲染特性,那么你就可以立即用上,而不需要在代码层有什么特殊的修改。D3将重点放在了数据与图形之间的绑定上。数据一般是json格式的对象,也可以是xml;而图形不仅包括SVG对象,也可以是html对象,或者其他浏览器所支持的图形对象。总之,同一组数据,你可以使用D3来创建一个HTML table,也可以创建一个SVG柱状图。

那么,D3是如何将数据与DOM节点之间绑定的呢?

第一步,是要选中DOM对象以构建选择区(selection)。 选中DOM对象的方式跟Jquery如出一辙,都是使用类似CSS选择器的语法,例如选中一组css类名为my-node的div节点并使之文字为白色:

 
1
d3.selectAll("div.my-node").style("color", "white");

第二步,就是将数据集绑定到选择区(selection)的DOM对象上。D3的提供一个十分有用的data函数,用以进行数据对象序列化和可能的预处理工作(详见API),并且它会把集合元素一个一个返回用以进行下一步处理。例如下面这个例子:

 
1
2
3
d3.selectAll("p")
    .data([4, 8, 15, 16, 23, 42])
    .style("font-size", function(d) { return d + "px"; });

在这个例子中,选择区(selection)中的每个P标签都与数据中的一个数字按顺序一一对应地绑定起来(我们假设P标签的个数与数组长度相等)。这样最后回调函数中,就可以取回被绑定的数据,从而动态地计算每个P标签中文字大小。熟悉jquery或者prototype类库的程序员都能很容易地发现他们之间的共相似之处,尤其是通过回调函数的方式来实现对一个集合中每个元素进行操作。

上面这个例子看起来很简单很容易理解。但是其中影藏一个重大的问题,就是数据集是经常变化的,一旦变化,那么数据集中的每个数据对象和选择区(selection)中的DOM对象不再一一对应了,那么多余的数据或者多余的dom对象该怎么处理呢?

为此,D3专门提供了一个enter, update, exit三个行为的数据集合(data)与选择区(selection)绑定的机制。要理解这个机制,最好还是得看图看例子,要不然不容易理解。这有一个d3的简单教程可以下载。下面这个图就是从该教程中摘出的D3数据绑定机制示意图,其解释如下:

  1. 数据集(data)和选择区(selection)中的对象应该是一一对应地绑定的。绑定的数据,一旦发生变化都会反映给对应的dom对象,这叫做update过程。
  2. 如果数据数量大于节点的数量,那么有一部分数据放不下了,将产生enter过程。
  3. 反之,如果数据从节点中取出来,导致节点空闲,这就发生exit的过程。

以上update, enter, exit三个过程,你都可以进行一系列自己特别定制。例如,通过ajax获取数据,初始化图形时,你可以通过定制enter过程来实现渐变地显示图形;在用户点击一个图形对象时,通过改变该图形对象所对应的数据数值,然后通过update过程来同时修改图形对象;当要删除某个图形对象时,触发exit过程,来实现渐隐的效果。于是,我们看到github上大量d3例子的代码,都类似如下分成三大块:update, enter, exit…

 
1
2
3
4
5
6
7
8
9
10
11
// Update…
var p = d3.select("body").selectAll("p")
    .data([4, 8, 15, 16, 23, 42])
    .text(String);
 
// Enter…
p.enter().append("p")
    .text(String);
 
// Exit…
p.exit().remove();

多说无用,我们还是来看具体的代码吧。我根据上文提到的教程中的案例创建了一个在线的例子:http://runjs.cn/detail/8enw0npq,在这里大家可以直接看到代码,我这里就不赘述了。大家可以看看d3的数据绑定机制究竟如何,enter, update, exit过程都是怎么工作的。

<iframe style=”width: 100%; height: 300px” src=”http://sandbox.runjs.cn/show/8enw0npq” allowfullscreen=”allowfullscreen” frameborder=”0″></iframe>

反思学习历程

就我的面试经验,国内的前端程序员大多数都是从jquery开始学javascript的。那么想必看完上面的代码,大家都会觉得跟jquery非常像,链式编程的风格,回调函数,很容易理解。

但为什么还说D3的学习曲线比较高呢?这是因为一般只看完一两个github上的D3 demo,没有专门的讲解,普通程序员还是难以彻底理解D3的那种以数据(以及容纳数据的容器)为核心的思路。至少我当初就没一下子搞明白为什么要搞update, enter, exit这么三个过程。这是因为常规的思维,对于图形操作,首先都把注意力集中在图形本身上。例如,一个通常的jquery程序员,遇到一个需求:在点击一个图形后将图形变大一倍同时把数据更新为原来的2倍。他通常都是这么构思整个流程的:先选中图形对象,改变图形,然后更新数据(或者先更新数据再改变图形)。虽然这样想逻辑很简单,但这样做无疑将数据和图形孤立了起来。如果这个图形还绑定了很多别的交互,数据集又很复杂,那么就会经常遇到顾头不顾腚的维护难题。D3处理交互逻辑时,通常是先通过图形对象找到数据,之后改变数据,最后再update更新图形对象。似乎转了一个圈才最后返回到图形本身,比起直接操作图形要麻烦。但是这里才是D3的精华所在。只有把复杂逻辑沉淀到数据上,才能在复杂交互的情况下保持代码的清晰性。

当然,如果你只是为了画几个图,并没有太多复杂交互,我认为D3就没多少优势了。有很多用jquery的chart插件实现的简单图表,并不比D3实现类似的案例多多少代码量,也能收到很好的效果。所以我以为D3的主要用武之地还是在进行较为复杂的交互式可视化项目开发时。而且,一旦理解了D3的数据驱动模式,思路就会广阔许多。将它与backbone,angularjs,ember.js等框架一做比较,确实地感到,所谓前端开发革命的浪潮,就是从数据驱动开始。

d3可视化实战02:理解d3数据驱动的真正含义的更多相关文章

  1. d3可视化实战00:d3的使用心得和学习资料汇总

    最近以来,我使用d3进行我的可视化工具的开发已经3个月了,同时也兼用其他一些图表类库,自我感觉稍微有点心得.之前我也写过相关文章,我涉及的数据可视化的实现技术和工具,但是那篇文章对于项目开发而言太浅了 ...

  2. d3可视化实战03:神奇的superformula

    需求驱动实现 前文讲过了D3的数据驱动机制,中间所举的例子都很简单.例如那个demo里面,绑定的数据是一个简单的数组,实现的图元也仅仅是一堆用SVG画的circle.但是现实世界中我们往往会遇到复杂的 ...

  3. d3可视化实战01:理解SVG元素特性

    一. SVG简介 ————————————————————————————————————————————————————————————————— SVG是一种和图像分辨率无关的矢量图形格式,它使用 ...

  4. d3可视化实战04:事件绑定机制

    首先说明,d3支持所有的JS事件——甚至其他代码的自定义事件.这里有一个列表,The MDN Event Reference, 包含了几乎所有浏览器创建的事件类型.大家有需要可以去查看. D3的事件绑 ...

  5. D3 数据可视化实战 笔记

    学习真是件奇妙的事情.这本书我之前都看过,有些的知识点却完全没有印象. 总结:把用到的知识好好研究:平时可以了解其他技术的基础,把相关的资料和难点记录下来. javascript陷阱 1.变量类型 v ...

  6. Pentaho6.1中D3可视化库的集成及数据联动的实现

    1.软件环境 操作系统版本:Win 10 64位 可视化图形库:D3 Pentaho版本: biserver-ce-6.1.0.1-196 2.对D3的简单介绍 D3允许你将任意的数据绑定到文档对象模 ...

  7. D3--数据可视化实战总结

    d3理解 标签(空格分隔): 未分类 1.绑定数据 [x] 定义:通过循环的方式将数据绑定在dom元素上,每个数据对应一个元素,所以这个数据的值就能来设定dom元素的width,height,x,y坐 ...

  8. [D3] 12. Basic Transitions with D3

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  9. [D3] 10. Creating Axes with D3

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

随机推荐

  1. C# 多线程经典示例 吃苹果

    本文主要讲述了多线程开发中经典示例,通过本示例,可以加深对多线程的理解. 示例概述: 下面用一个模拟吃苹果的实例,说明C#中多线程的实现方法.要求开发一个程序实现如下情况:一个家庭有三个孩子,爸爸妈妈 ...

  2. 黑马程序员_Java基础组成

    Java语言基础组成 2.1关键字 main不是关键字,但被JVM所识别的名称. 关键字的定义和特点 定义:被Java语言赋予了特殊含义的单词. 特点:关键字中所有字母都为小写. 用于定义数据类型的关 ...

  3. Java中的局部代码块、构造代码块、静态代码块

    局部代码块: 作用:控制变量的生命周期: 在程序中,当我们已经使用完 x 后,并且在接下来的代码中,不会再用到x,那么就没必要让x 在内存中占用空间了,这用情况下,可以使用 局部代码块,将x及其所设计 ...

  4. Hdu 1856(离散化+并查集)More is better

    题意:一些人遵循朋友的朋友也是朋友原则,现在找出最大的朋友圈, 因为人的编号比较大,但是输入的数据最多是10w行,所以可得出最多也就20w人,所以可以进行一下离散化处理,这样数据就会毫无压力 //// ...

  5. kubernetes组件

    kubernetes组件 @(马克飞象)[k8s] 组件 kubernetes除了必备的dns和网络组件外,官方推出大量的cluster-monitoring,dashboard,fluentd-el ...

  6. 【AngularJS入门】用ng-repeat指令实现循环输出

    循环输出列表很多项目在web服务端做,前端做好模版后后端写jsp代码,双方需要紧密合作,分清责任.有些项目由后端提供restful方法,前端用ajax调用自己循环,这种一般是大把的jquery拼字符串 ...

  7. ffmpeg错误隐藏框架分析

    本文主要是分析ffmpeg的错误隐藏框架,故解码流程此处不会特地进行讨论,网上其他地方其实也有不少介绍相关流程的了,但发现基本没有介绍错误隐藏流程的,故本文希望能填补这个空白. 我们直接从decode ...

  8. JAVA设计模式(09):结构型-代理模式(Proxy)

    代理模式是经常使用的结构型设计模式之中的一个,当无法直接訪问某个对象或訪问某个对象存在困难时能够通过一个代理对象来间接訪问,为了保证client使用的透明性,所訪问的真实对象与代理对象须要实现同样的接 ...

  9. [Falcor] Retrieving Multiple Values

    In addition to being able to retrieve a path from a Falcor Model, you can also retrieve multiple Pat ...

  10. 再次记录老K站点的工作策略

    股市开盘了. 据说今天是多空决战的日子. 7月17日.三大期指交割. 打开大盘,看着指数一会上升,一会跳水.好不欢乐.当然,今天我是来记录我的老K,关于老K的下一步. 近期每天傍晚的时候.都会去江边散 ...