Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

D3 介绍

Posted on 10/31/201210/08/2024 by 四火

bubbleMap D3.js 是一个基于数据的操作文档的 JavaScript 库,可以让你绑定任何数据到 DOM,支持 DIV 这种图案生成,也支持 SVG 这种图案的生成(如果你对 SVG 不熟悉,请先看一下这篇文章,它介绍了 SVG、VML 和 Canvas)。D3 帮助你屏蔽了浏览器差异,做出来图案的效果可以说是炫目得一塌糊涂,可是代码却很简洁。在我第一次听人介绍 D3 的时候,确实被其示例震撼到了,大量的例子在这里可以找到。

data_join

这是 D3 以数据为核心的一个示意图,可以简单这样来解释:有一个选择区(selection),存在若干节点(node),因此可以容纳若干数据(data),最大可容纳数据的量等于节点的个数,即数据和节点一一对应,数据存放到节点中被称为绑定(bound to)。

  1. 如果节点的数据发生变化,这样的行为叫做 update;
  2. 如果数据数量大于节点的数量,那么有一部分数据放不下了,将产生 enter 行为;
  3. 反之,如果数据从节点中取出来,导致节点空闲,这就发生 exit 的行为。

 

初始感官认识:

通过下面这个例子 d3 例子

image

实现上,存在 6 个 circle 的 DOM 对象:

    <svg id="vis">
      <circle></circle>
      <circle></circle>
      <circle></circle>
      <circle></circle>
      <circle></circle>
      <circle></circle>
    </div>

在点击 Datasets 不同行的时候,数据的个数一会儿大于 6,一会儿小于 6,在变化过程中分别触发 enter/update 和 exit/update 的行为。可以看到左侧的球在红色边框的区域内进进出出,主要代码如下:

      var datasets = [
        [80,20,35,48,120,380],
        [60,50,80,90,210,440],
        [100,80,300,240,20,340,70,40],
        [80,30,400]
      ];
      
      var currentDataset = 0;
      
      var render = function(datasetIndex){
        var data = datasets[datasetIndex];
        var circles = d3.select('#vis').selectAll('circle');
        
        circles.data(data)
          .style('fill', '#1CA2DA')
          .transition()
          .duration(800)
            .attr('r', 15)
            .attr('cx', function(d, i){ return i * 60 + 20; })
            .attr('cy', function(d){ return d; });
        //update
            
        circles.data(data)
          .enter()
            .append('circle')
            .attr('r', 15)
            .attr('cx', 0)
            .attr('cy', 0)
            .style('opacity', 0)
            .style('fill', 'red')
            .transition()
              .duration(1000)
              .style('opacity', 1)
              .attr('cx', function(d, i){ return i * 60 + 20; })
              .attr('cy', function(d){ return d; });
        //超出容量的数据,enter
            
        circles.data(data)
          .exit()
            .transition()
              .duration(800)
              .style('opacity',0)
              .remove();
        //离开选择区的数据,exit
          
      }; 
      
      render(0);
      
      var changeDataset = function(d, i){
        d3.selectAll('.dataset').attr('class', 'dataset');
        this.setAttribute('class', 'dataset active');
        render(this.getAttribute('data-index'));
      };
      
      d3.selectAll('.dataset').on('click', changeDataset);

我想如果你习惯阅读 JQuery 代码,那么这样的代码很容易理解,链式编程的风格,清晰自然。以容器+数据的映射关联关系为核心,有点像状态机,但又不完全像,不同状态下基于其 update、enter 或者 exit 的行为绑定动作和状态属性的改变。

 

进一步介绍:

选择器:用惯了 JQuery 的话,这个没有什么可说的,比如这样的例子:

d3.select('#vis').append('div').style('top', '20px').style('left','20px');

会输出一个绿色的矩形。

动态属性:D3 支持这种以 function 方式传入的属性,这样的属性是动态的,每次执行的时候再去调用计算获得:

d3.selectAll("p").style("color", function() {
  return "hsl(" + Math.random() * 360 + ",100%,50%)";
});

enter 和 exit:前文也已经提到了,当数据绑定到选择区对象上的时候,数据的每一个元素都会和选择区对象的每一个节点对应起来,节点内的数据发生变化,就是 update;节点内的数据移除,节点空出来,就是 exit;数据数量大过节点,造成数据剩余,就是 enter。然后就可以基于这个自定义这些事件发生的时候需要进行的行为和变更的状态了:

// 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();

转换,而非呈现(Transformation, not Representation):D3 并不是一个新的图像呈现类库,因此它和 Raphaël 是不一样的。你可以用 D3 加上自己定义的 CSS 来创建 SVG 图案,浏览器未来的特性也会被 D3 封装起来给你用,这些事情无非是让你对 DOM 和其上的数据的操作换了一种形式而已。

过渡(Transitions):这指的是图案从一种状态变化到另一种状态的时候,中间的动画过渡效果。D3 支持几种渐变的风格,帧速很高,实际上还是 CSS3 的渐变,但是对开发人员来说好用多了。

当然,直接拿 D3 来绘制图表可能会觉得繁琐,如果使用它的扩展就方便多了。

————————————————————————————————————-

2012 年 11 月 9 日:

有同事说这个东西太烂了,学习曲线太高,不容易掌握,而且要做一张图表的话,和一些 JQuery 的图标插件比起来,代码量也不少。

其实,我倒觉得还好,d3 功能比较强大,但是很多人不喜欢的主要原因是,这个东西是不符合人类常规思维的,它是那种以数据(以及容纳数据的容器)为核心的代码风格,以这个折线图为例:

image

如果用 SVG 来实现它的话,一般都要使用 path 标签了,关键代码包括,一个是计算点坐标的代码:

var line = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.close); });

还有一个是绘制折线的代码:

svg.append("path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);

另外,计算逻辑从时间上的滞后,即回调函数的使用也是破坏正常思维逻辑的一个因素。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

×Scan to share with WeChat

你可能也喜欢看:

  1. JavaScript 实现继承的几种方式
  2. A page widgetization practice
  3. Javascript Memoizer
  4. 几道容易出错的 JavaScript 题目
  5. Function Invocation Patterns

2 thoughts on “D3 介绍”

  1. 四火 says:
    11/14/2012 at 5:45 PM

    这个链接汇聚了一些 d3 的学习材料。

    Reply
  2. tcdona says:
    10/31/2012 at 9:21 AM

    感谢分享,终于见到对 d3 的相关分析了~~

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Spark 互联网 亚马逊 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 眼界 程序员 管理 系统设计 缓存 编程范型 美股 英语 西雅图 设计 问题 面向对象 面试

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Machine Learning and Artificial Intelligence (6)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 聊一聊分布式系统中的时间
  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • Ticket: TRANSACTION 1.922915 BTC. Go to withdrawal >> https://yandex.com/poll/enter/BXidu5Ewa8hnAFoFznqSi9?hs=20bd550f65c6e03103876b28cabc4da6& on 倔强的程序员
  • panshenlian.com on 初涉 ML Workflow 系统:Kubeflow Pipelines、Flyte 和 Metaflow
  • panzhixiang on 关于近期求职的近况和思考
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme