SHIHUC

好记性不如烂笔头,还可以分享给别人看看! 专注基础算法,互联网架构,人工智能领域的技术实现和应用。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

D3的基本设计思路

Posted on 2016-11-15 14:02  shihuc  阅读(3218)  评论(0编辑  收藏  举报

学习一项新技术,首先要搞清楚它的基本设计思路,有了这个宏观的技术架构,使用该技术起来,就会得心应手了。否则,就会不知道如何下手,即使看到人家的例子程序,可能也不知其所以然。

 

下面,就简单的结合自己研究的官方文档,对D3的使用,给其基本设计思路,做一个简单的描述:

 

在html文件中加载完官方的js插件d3.v3.min.js后:

1.  设计画布(这里主要基于SVG介绍,当然,画布其实还有Canvas)。

     a. 主要包括SVG的大小,含有width,以及height。

     b. 通过d3全局对象,构建svg对象。

 

2. 创建视图(D3支持的视图很多)

 1 [[bundle|捆绑布局]] - 对边使用Holten 层次捆绑算法。
 2 [[chord|弦布局]] - 从关系矩阵生成一个弦图。
 3 [[cluster|簇布局]] - 将实体聚集成树状图。
 4 [[force|力布局]] - 模拟物理力排放相连节点的位置。
 5 [[hierarchy|层次布局]] - 这是个抽象布局,可派生一个定制的层次布局。
 6 [[histogram|直方图布局]] - 使用量化的箱计算数据的分布。
 7 [[pack|包布局]] - 用递归的圆形包装生成一个层次布局。
 8 [[partition|分区布局]] - 递归地将节点树分割为旭日状或者冰柱状。
 9 [[pie|饼布局]] - 计算饼图或圆环图中弧的开始和结束角度。
10 [[stack|堆叠布局]] - 计算堆叠图或者面积图的基线。
11 [[tree|树布局]] - 整齐地排列树节点。注意簇布局不是整齐的。
12 [[treemap|矩形树布局]] - 使用空间递归分区算法展示树的节点。

   例如:

          var tree = d3.layout.tree();

 

3. 数据绑定

    其实,这一步做的事情,就是一个视图与数据的结合,视图将数据转化为该视图内定的数据结构,重点是添加了一些D3功能相关的辅助参数或者变量。 例如上例中的树视图,数据绑定后过程如下:

1 var nodes = tree.nodes(root).reverse(),
2 var links = tree.links(nodes);

这个绑定,也可以说是数据转化,之后,nodes对象中不仅含有root这个原始数据(用户提供的输入数据),还含有D3系统需要的辅助参数,比如parent,depth等。

 

4.  视图数据结合

     这一步,其实最能体现D3的设计思想,这一步涵盖的内容最为丰富,但是不多讲,重点介绍D3的特色操作enter,update,exit。

     a. 获取新的选择器(SVG灌入绑定数据后的新对象)

         例如: 

               var node = svg.selectAll("g.node").data(nodes, function(d) { return d.id || (d.id = ++i); });

     b. enter/update/exit

        这三个概念是什么含义呢?

        如果数组为 [3, 6, 9, 12, 15],将此数组绑定到三个 p 元素的选择集上。可以想象,会有两个数据没有元素与之对应,这时候 D3 会建立两个空的元素与数据对应,这一部分就称为 Enter。而有元素与数据对应的部分称为 Update。如果数组为 [3],则会有两个元素没有数据绑定,那么没有数据绑定的部分被称为 Exit。

        例如下图:

        

        对于图形存在交互操作的情景,enter,update,以及exit都会用得到,例如我上一篇博客D3树状图异步按需加载数据里面的树状图,点击节点会有展开和收缩的效果,这个时候三者都会参与实际的逻辑处理。

        

     Update 和 Enter 的使用

        当对应的元素不足时 ( 绑定数据数量 > 对应元素 ),需要添加元素(append)。

        现在 body 中有三个 p 元素,要绑定一个长度大于 3 的数组到 p 的选择集上,然后分别处理 update 和 enter 两部分。

 1 var dataset = [ 3 , 6 , 9 , 12 , 15 ];
 2 
 3 //选择body中的p元素
 4 var p = d3.select("body").selectAll("p");
 5 
 6 //获取update部分
 7 var update = p.data(dataset);
 8 
 9 //获取enter部分
10 var enter = update.enter();
11 
12 //update部分的处理:更新属性值
13 update.text(function(d){
14     return "update " + d;
15 });
16 
17 //enter部分的处理:添加元素后赋予属性值
18 enter.append("p")
19     .text(function(d){
20         return "enter " + d;
21     });
  • update 部分的处理办法一般是:更新属性值
  • enter 部分的处理办法一般是:添加元素后,赋予属性值

     

    Update 和 Exit 的使用

      当对应的元素过多时 ( 绑定数据数量 < 对应元素 ),需要删掉多余的元素。

      现在 body 中有三个 p 元素,要绑定一个长度小于 3 的数组到 p 的选择集上,然后分别处理 update 和 exit 两部分。

      

 1 var dataset = [ 3 ];
 2 
 3 //选择body中的p元素
 4 var p = d3.select("body").selectAll("p");
 5 
 6 //获取update部分
 7 var update = p.data(dataset);
 8 
 9 //获取exit部分
10 var exit = update.exit();
11 
12 //update部分的处理:更新属性值
13 update.text(function(d){
14     return "update " + d;
15 });
16 
17 //exit部分的处理:修改p元素的属性
18 exit.text(function(d){
19         return "exit";
20     });
21 
22 //exit部分的处理通常是删除元素
23 // exit.remove();
  • exit 部分的处理办法一般是:删除元素(remove)

 

     到此, 入门D3,了解这个基本的框架,再去细读API文档或者教程,相对会容易些!

 

     最后,附带一个简单的例子,绘制环状图(显示资源占用比例的场景,还是很有使用价值的):

     

 1 <html>  
 2   <head>  
 3         <meta charset="utf-8">  
 4         <title>环装图</title>  
 5   </head> 
 6 
 7 <style>
 8 
 9 
10 </style>
11     <body>  
12         <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>  
13         <script>
14         
15         var width = 400;
16         var height = 400;
17         var dataset = [ 30 , 10 , 43 , 55 , 13 , 11, 100, 99];
18         
19         var svg = d3.select("body")
20                     .append("svg")
21                     .attr("width", width)
22                     .attr("height", height);
23         
24         var pie = d3.layout.pie();
25 
26         var piedata = pie(dataset);
27         
28         var outerRadius = 150;    //外半径
29         var innerRadius = 100;    //内半径,为100则中间没有空白
30 
31         var arc = d3.svg.arc()    //弧生成器
32                     .innerRadius(innerRadius)    //设置内半径
33                     .outerRadius(outerRadius);    //设置外半径
34         
35         var color = d3.scale.category20c();
36         
37         var arcs = svg.selectAll("g")
38                       .data(piedata)
39                       .enter()
40                       .append("g")
41                       .attr("transform","translate("+ (width/2) +","+ (width/2) +")");
42                       
43         arcs.append("path")
44             .attr("fill",function(d,i){
45                 return color(i);
46             })
47             .attr("d",function(d){
48                 return arc(d);
49             });
50         
51         arcs.append("text")
52             .attr("transform",function(d){
53                 return "translate(" + arc.centroid(d) + ")";
54             })
55             .attr("text-anchor","middle")
56             .text(function(d){
57                 return d.data;
58             });          
59         </script>  
60         
61     </body>  
62 </html>