进阶总结

最后更新于:2022-04-01 20:05:02

进阶系列的文章从去年10月开始写的,晃眼又是4个多月了,想在年前总结一下。 首先恭祝大家新年快乐。今年是羊年吧。前段时间和朋友聊天,聊到十二生肖里为什么没猫,我张口就道:不是因为十二生肖开会的时候猫迟到了吗? 呵呵,不知道这是谁给我灌输的观点。o(>﹏<)o 进阶系列的文章分为两部分,文章前括号里写有: - 【D3.js 进阶系列】 - 【D3.js 选择集与数据详解】 虽然称之为“进阶”,但并不是说一定要看完“入门”才能看。由于本人能力有限,不能很好地整理成由易到难的学习文章。请大家挑选自己需要的阅读。 本人写文章主要也是一个自我学习的过程,错漏很多,诚心希望大家给予纠正建议。 文章前标有【D3.js 进阶系列】的文章如下: | 1.0 | [CSV 表格文件的读取](http://www.ourd3js.com/wordpress/?p=430) | |-----|-----| | 1.1 | [其他表格文件的读取](http://www.ourd3js.com/wordpress/?p=501) | | 1.2 | [读取 CSV 文件时乱码的解决方法](http://www.ourd3js.com/wordpress/?p=519) | | 2.0 | [力学图 + 人物关系图](http://www.ourd3js.com/wordpress/?p=555) | | 2.1 | [力学图的事件 + 顶点的固定](http://www.ourd3js.com/wordpress/?p=606) | | 2.2 | [力学图的参数](http://www.ourd3js.com/wordpress/?p=613) | | 3.0 | [分区图](http://www.ourd3js.com/wordpress/?p=643) | | 3.1 | [圆形分区图](http://www.ourd3js.com/wordpress/?p=653) | | 3.2 | [分区图的函数](http://www.ourd3js.com/wordpress/?p=656) | | 4.0 | [绘制箭头](http://www.ourd3js.com/wordpress/?p=660) | | 5.0 | [直方图](http://www.ourd3js.com/wordpress/?p=684) | | 6.0 | [拖拽的应用(Drag)](http://www.ourd3js.com/wordpress/?p=714) | | 6.1 | [缩放的应用(Zoom)](http://www.ourd3js.com/wordpress/?p=720) | | 6.2 | [饼状图的拖拽](http://www.ourd3js.com/wordpress/?p=728) | 文章前标有【D3.js 选择集与数据详解】的文章如下: | 1 | [使用datum()绑定数据](http://www.ourd3js.com/wordpress/?p=747) | |-----|-----| | 2 | [使用data()绑定数据](http://www.ourd3js.com/wordpress/?p=797) | | 3 | [绑定数据的顺序](http://www.ourd3js.com/wordpress/?p=811) | | 4 | [enter和exit的处理方法以及处理模板](http://www.ourd3js.com/wordpress/?p=822) | | 5 | [处理模板的应用](http://www.ourd3js.com/wordpress/?p=841) | 很感谢大家在每一篇文章下的留言,我收到了很多建议,也得到了很多鼓励,在这里向大家表示感谢。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2015 年 2 月 17 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

处理模板的应用

最后更新于:2022-04-01 20:04:59

在【[选择集与数据 - 4](http://www.ourd3js.com/wordpress/?p=822)】一文中,介绍了一个update、enter、exit的处理模板,这个模板很常用,本文将通过一个例子来讲解其使用方法。 ## 1. 模板 复习一下上一章提到的模板。 ~~~ //绑定数据后,分别返回update、enter、exit部分 var update = selection.data(dataset); var enter = update.enter(); var exit = update.exit(); //1.update部分的处理方法 update.text( function(d){ return d; } ); //2.enter部分的处理方法 enter.append("p") .text( function(d){ return d; } ); //3.exit部分的处理方法 exit.remove(); ~~~ ## 2. 应用模板的场合 当数据需要更新(添加、删除、变更)的时候,要想起此模板。 ## 3. 应该该模板的柱形图 下面制作一个柱形图,用于理解更新数据与使用该模板的好处。柱形图的数据有时候需要更新,更新后柱形图也需要跟着变化。例如将数据排序、增加新的数据等,都需要柱形图跟着变化。在这里只绘制柱形图的矩形和文字,不绘制坐标轴,然后再添加两个按钮,用于更新数据。将绘制图形的代码写在一个函数draw()里,当数据发生更新时,再次调用此函数即可。 ~~~ function draw(){ //获取矩形的update部分 var updateRect = svg.selectAll("rect") .data(dataset); //获取矩形的enter部分 var enterRect = updateRect.enter(); //获取矩形的exit部分 var exitRect = updateRect.exit(); //1. 矩形的update部分的处理方法 //2. 矩形的enter部分的处理方法 //3. 矩形的exit部分的处理方法 //获取文字的update部分 var updateText = svg.selectAll("text") .data(dataset); //获取文字的enter部分 var enterText = updateText.enter(); //获取文字的exit部分 var exitText = updateText.exit(); //1. 文字的update部分的处理方法 //2. 文字的enter部分的处理方法 //3. 文字的exit部分的处理方法 } ~~~ 上述模板中,分别获取矩形和文字的update、enter、exit三个部分。然后再分别对三个部分进行相应的处理。下面以矩形为例,来讲解怎么样分别处理。代码如下: ~~~ //1. 矩形的update部分的处理方法 updateRect.attr("fill","steelblue") //设置颜色为steelblue .attr("x", function(d,i){ //设置矩形的x坐标 return padding.left + i * rectStep; }) .attr("y", function(d){ //设置矩形的y坐标 return height- padding.bottom - d; }) .attr("width",rectWidth) //设置矩形的宽度 .attr("height",function(d){ //设置矩形的高度 return d; }); //2. 矩形的enter部分的处理方法 enterRect.append("rect") .attr("fill","steelblue") //设置颜色为steelblue .attr("x", function(d,i){ //设置矩形的x坐标 return padding.left + i * rectStep; }) .attr("y", function(d){ //设置矩形的y坐标 return height- padding.bottom - d; }) .attr("width",rectWidth) //设置矩形的宽度 .attr("height",function(d){ //设置矩形的高度 return d; }); //3. 矩形的exit部分的处理方法 exitRect.remove(); ~~~ update部分的处理方法是更新属性,enter部分的处理方法是添加元素后再赋予其相应的属性,exit部分的处理方法则是删除掉多余的元素。这么处理之后,对于原数组dataset,无论是排序还是增减数据,图表都能够自动发生相应变化。下面在HTML中分别添加两个按钮,一个用于排序,一个用于增加数据。在HTML中的里添加以下两个按钮: ~~~ ~~~ 给两个按钮的定义了两个事件函数,但单击事件发生时,分别调用mysort()和myadd()。这两个函数的实现很简单,只要将数据处理后,再调用一次draw()重绘一次即可。 ~~~ function mysort(){ dataset.sort(d3.ascending); //排序 draw(); } function myadd(){ dataset.push( Math.floor(Math.random() * 100) ); //添加一个项 draw(); } ~~~ 添加按钮之后,结果下所示: 由于边界有限,增加多个数据后矩形会在边界之外,但是不妨碍本文要表达的意思。 源代码可打开下面网址后,右键查看源代码: [http://www.ourd3js.com/demo/template.html](http://www.ourd3js.com/demo/template.html) 谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2015 年 2 月 7 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

enter和exit的处理方法以及处理模板

最后更新于:2022-04-01 20:04:57

绑定数据之后,选择集分为三部分:update、enter、exit。这三部分的处理办法是什么呢?本文将讲解其处理方法,以及一个常用的处理模板。 ## 1. enter的处理方法 如果没有足够的元素,那么处理方法通常是使用append()添加元素。请看下面的代码: ~~~

~~~ 本例中,body中的p元素只有一个,但是数据有三个,因此enter部分包含多余的两个数据。对多余数据的处理方法就是append元素,与之对应。经过处理后,body里有三个p元素,内容分别为: ~~~

3

6

9

~~~ 通常,从服务器读取文件后,数据是有的,但是网页中是没有元素的。这是D3一个很重要的特性,即可以选择一个空集,然后使用enter().append()的形式来插入元素。假设现在body里没有p元素,请看如下代码: ~~~ var dataset = [10,20,30,40,50]; var body = d3.select("body"); body.selectAll("p") //选择body中所有p,但由于没有p,所以选择了一个空集 .data(dataset) //绑定dataset数组 .enter() //返回enter部分 .append("p") //添加p元素 .text(function(d){ return d; }); ~~~ 上述代码中,selectAll选择了一个空集,然后绑定了数据。由于选择集为空,那么data()返回的update部分为空。然后调用enter()和append(),使得每一个数据都有元素p与之对应。最后再更改p元素的内容。即enter部分的常见处理方法是使用append()添加元素。 ## 2. exit的处理方法 有多出的元素,没有数据与之对应。对于这样的元素,通常的做法是使用remove()删除元素。假设body中有5个p元素,请看如下代码: ~~~ var dataset = [10, 20, 30]; var p = d3.select("body").selectAll("p"); //绑定数据之后,分别获取update部分和exit部分 var update = p.data(dataset); var exit = update.exit(); //update的部分的处理方法是修改内容 update.text( function(d){ return d; } ); //exit部分的处理方法是删除 exit.remove(); ~~~ 这段代码中,对于exit部分的处理方法是删除。删除之后,网页中将不会有多余的p元素。 ## 3. 处理模板 经过上两节的内容,知道了如何处理多余的数据和元素。但是,有时候我们不知道是数据多,还是元素多,或者允许用户决定谁多谁少。对于事前不知道数组长度或元素数量的问题,可定义一套处理的模板。请看如下代码: ~~~ var dataset = [10, 20, 30]; var p = d3.select("body").selectAll("p"); //绑定数据后,分别返回update、enter、exit部分 var update = p.data(dataset); var enter = update.enter(); var exit = update.exit(); //1.update部分的处理方法 update.text( function(d){ return d; } ); //2.enter部分的处理方法 enter.append("p") .text( function(d){ return d; } ); //3.exit部分的处理方法 exit.remove(); ~~~ 如此,则不需要考虑网页中是否有足够的p元素,或者有多余的p元素,无论是何种情况,最终的结果必定是一个p元素对应数组中的一个项,没有多余的。这种方法,可称为有一套处理的**模板**,在数据需要经常更新时很常用。谢谢阅读。下一篇文章将会讲述如何应用该模板。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2015 年 1 月 27 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

绑定数据的顺序

最后更新于:2022-04-01 20:04:55

data() 函数有两个参数,第一个是被绑定数据,第二个参数用于指定绑定的顺序。在数据需要更新的时候常常会用到。 默认的情况下,data()函数是按照索引号依次绑定数组各项的。第0个元素绑定数组的第0项,第1个元素绑定数组的第1项,依此类推。也可以不按照此顺序进行绑定,这就要用到data()的第二个参数。这个参数是一个函数,称为键函数(key function)。 要注意,只有在选择集原来已经绑定有数据的情况下,才能使用键函数指定绑定的顺序。请看以下代码: ~~~

~~~ 这段代码对p元素的内容进行了修改,修改之后的p元素为: ~~~

3 : 张三

6 : 李四

9 : 王五

~~~ 下面将persons里的数据更新,再绑定一次数据。本次绑定添加键函数: ~~~ //更新persons里的数据 persons = [ { id: 6 , name:"张三" }, { id: 9 , name:"李四" }, { id: 3 , name:"王五" }]; //根据键函数的规则绑定数据,并修改内容 p.data(persons, function(d){ return d.id; }) .text(function(d){ return d.id + " : " + d.name; }); ~~~ 键函数里只有一个语句return d.id。表示使用数组项的id属性作为**键**。使用本次绑定的数据修改p元素的内容后,结果如下: ~~~

3 : 王五

6 : 张三

9 : 李四

~~~ 可以看到,结果并没有按照新persons数组的次序(6:张三、9:李四、3:王五)排列。绑定过程如图1所示,绑定的顺序不按照索引号绑定,而是使**键**值依次对应。 [![4-4-12](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417c248caa.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-121.png) 图1 谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2015 年 1 月 17 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

使用data()绑定数据

最后更新于:2022-04-01 20:04:53

D3 中绑定数据大多是由 data() 函数来完成的,它是怎样工作的,它与 datum() 有什么区别呢? data()函数能够将数组各项分别绑定到各元素上,而且能够设置绑定的规则。data()还能够处理数组长度与元素数量不一致的情况。当数组长度大于元素数量,能为多余数据预留元素位置,以便将来插入新元素;当数组长度小于元素数量时,能提供指向多余元素的方法,以便将来删除。下面来剖析data()是如何绑定数据的,相比datum()有哪些新功能。 ## data()的工作过程 假设body中有三个段落元素p,HTML代码如下: ~~~

Lion

Tiger

Leopard

~~~ 要将一个数组的各项分别绑定到各元素上,假设要绑定的数组为[3,6,9],那么我们希望第一个p元素绑定3,第二个绑定6,第三个绑定9。这种情况就需要使用data()函数,如果使用datum(),则会将数组本身绑定到各元素上,即第一个p元素绑定[3,6,9],第二个绑定[3,6,9],第三个也是绑定[3,6,9],其区别如图1所示。 [![4-4-6](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41785c109b.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-61.png) 图1 使用data()绑定数据的代码如下: ~~~ //定义数组 var dataset = [3, 6, 9]; //选择body中的p元素 var p = d3.select("body").selectAll("p"); //绑定数据到选择集 var update = p.data(dataset); //输出绑定的结果 console.log(update); ~~~ 这段代码中,将数组绑定到选择集并输出结果。如图2所示,数组的三项分别被绑定到了个元素上,与图2的预测一致。[![4-4-7](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41785d7e98.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-71.png) 图2 上例中,数组长度与元素数量正好相等。两者也有不相等的情况,如果数组长度为5,而元素数量为3,则多出2个数据没有绑定元素。如果数组长度为1,元素数量为3,则会有2个元素没有绑定数据。在D3中,根据数组长度和元素数量的关系,分别把各种情况称为: - update:数组长度 = 元素数量 - enter:数组长度 > 元素数量 - exit:数组长度 < 元素数量 这三个单词的含义可能很难理解,update的原意为“更新”,enter的原意为“进入”,exit的原意为“退出”,直译的结果很难表现所需的意思。其实,在数据可视化中,手中的数据通常都是要进行可视化的,而没有绑定数据的元素是没有用的。那么对于这三个单词,我们可以理解为:如果数组长度大于元素数量,则多余的数组项“即将进入可视化(enter)”;如果数组长度小于元素数量,则多余的元素“即将退出可视化(exit)”;如果数组长度等于元素数量,元素上的数据“得到了更新(update)”。 还是很难理解吗?没关系,请看图3。其中,左图表示数组长度为5、元素数量为3的情况,那么有两个数组项没有与之相连的元素,这一部分被称为enter。右图表示数组长度为1、元素数量为3的情况,那么有两个元素没有数组项与之相连,这一部分称为exit。数组项和元素相连的部分被称为update。 [![4-4-8](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-19_57161004bf1cb.jpg)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-81.png) 图3 data()函数返回一个对象,对象里包含update部分和两个函数。一个是enter()函数,返回enter部分,一个是exit()函数,返回exit部分。请看如下代码: ~~~ var dataset = [3, 6, 9, 12, 15]; var p = d3.select("body").selectAll("p"); var update = p.data(dataset); console.log(update); console.log(update.enter()); console.log(update.exit()); ~~~ 这段代码中,数组长度为5,元素数量为3,多出两个数组项。其输出结果如图4和5所示。 [![4-4-9](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417860712a.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-91.png) 图4 图4中,可以看到被绑定数据的三个p元素。还有enter()和exit()两个函数,用于返回本次绑定中enter和exit部分。 [![4-4-10](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417c21a56a.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-101.png) 图5 图5中,可以看到enter部分中,D3已经为多余的数组项12和15预留了位置,用于将来的操作。enter部分中还有一个update变量,指向update部分。本次绑定中,没有多余的元素,所以exit中没有内容。如果将数组换成: ~~~ var dataset = [3]; ~~~ 则exit部分的输出结果如图6所示,可以看到多出的两个p元素。 [![4-4-11](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417c233f11.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-111.png) 图6 谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2015 年 1 月 17 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

使用datum()绑定数据

最后更新于:2022-04-01 20:04:50

选择集和数据的关系是 D3 最重要的基础,在【[入门 - 第 7 章](http://www.ourd3js.com/wordpress/?p=149)】时进行过些许讲解,对于要掌握好 D3 是远远不够的。故此开设一个新的分类,专门讨论选择集与数据的关系,包括数据绑定的使用和工作原理,update 、enter、exit 的原理和使用方法等,接下来一段时间里会有多篇此类文章。 D3 最大的特色就是能够将数据绑定到DOM上。使用select或selectAll选择元素之后,被选择的元素上是没有数据的。数据绑定就是使被选择元素里包含有数据。与此相关的函数有两个: - datum():将指定数据赋值给被选择元素。 - data():将数据数组与选择集的元素结合。 上面的概念可能难以理解,不要着急,接下来依次剖析datum()和data(),来看看数据绑定是如何工作的,它们又有什么不同之处。虽然不理解原理也可直接使用这两个函数,但遇到意料之外的结果时往往会不知道如何调试,无从下手,因此大致知道其工作过程是必要的。 ## datum()的工作过程 datum() 绑定数据的方法很简单,在 D3 中使用较少,但能帮助你理解数据 D3 是如何绑定数据的。请先看下面的代码: ~~~

Fire

Water

Wind

~~~ 这段代码中,使用datum()将数值7绑定到了选择集上,然后在控制台输出该选择集。在浏览器的控制台中,可以看到如图1所示的输出结果。其中包含有三个p元素,正是使用selectAll选择的三个段落,还可看到选择集的大小(length)、父节点(parentNode)等信息。 [![4-4-1](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b4178545670.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-1.png) 图1 展开任意一个p元素,其各属性如图2所示。可以看到,经过绑定之后,多出了一个__data__属性,其数值7正是刚才绑定的数据。展开其他的p元素,会发现每一个元素中都多出了一个__data__,并且数值都是7。 [![4-4-2](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417855b35e.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-2.png) 图2 那么datum()的工作过程就再明了不过了,即对于选择集中的每一个元素,都为其增加一个__data__属性,属性值为datum(value)的参数value。此处的value并非一定要是number(数值)型,也可以是string(字符串)、boolean(布尔型)和object(对象),无论是什么类型,其工作过程都是给__data__赋值。如果使用undefined和null作为参数,则将不会创建__data__属性。下面来看看datum()的源代码: ~~~ d3_selectionPrototype.datum = function(value) { return arguments.length ? this.property("__data__", value) : this.property("__data__"); }; ~~~ 由上面的源代码可以知道,其实datum()是用D3的property()函数实现的:如果有参数value,则调用property给当前对象添加一个__data__属性,否则返回__data__属性值。下面来试验一下没有参数的情形: ~~~ var p = d3.select("body").selectAll("p"); p.datum(7); console.log( p.datum() ); //在控制台输出被绑定的数据 ~~~ 这段代码将在控制台输出数字7,正是被绑定的数据。现有有一个问题,数据被绑定在选择集上后,该如何使用呢,或者说D3希望我们如何使用呢。下面举一个例子,使用被绑定的字符串,替换掉原字符串: ~~~

Fire

Water

Wind

~~~ 这段代码中,使用datum()绑定了一个字符串Thunder到选择集上,然后调用text()替换字符串。text()用于设置或获取被选择元素的文本。text()的参数是一个无名函数function(d,i),这两个参数分别代表数据(datum)和索引(index)。这两个参数的名称也可以不使用d和i,但意义是不变的。在D3中,建议写成d和i。最后,在这个无名函数里返回了由d和i结合而成的字符串,中间加一空格。结果如图3所示,网页中的三个段落元素p的字符串被替换成:Thunder 0、Thunder 1、Thunder 2。 [![4-4-3](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417857bab5.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-3.png) 图3 由结果可知,无名函数的两个参数d和i,d表示被绑定的数据,i表示的索引号是从0开始的。在D3中使用被绑定的数据都是使用上述形式,即定义一个无名函数function(d,i),然后在函数的实现中使用d和i。D3还有一个特性,能使被绑定的数据传递给子元素。对前一段代码稍作修改: ~~~ p.datum("Thunder") .append("span") //在每一个被选择元素后添加元素span .text(function(d,i){ return " " + d; }); ~~~ 结果如图4所示,各段落元素的末尾被添加了span元素,内容为Thunder。 [![4-4-4](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417858f0f2.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-4.png) 图4 下面使用console.log在控制台输出选择集p,输出结果如图5所示。可以看到,子元素span里也含有属性__data__,属性值也是字符串Thunder。于是可以得出一个结论:在被绑定数据的选择集中添加元素后,新元素也会具有被绑定数据。 [![4-4-5](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41785a6137.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-5.png) 图5 下一章讲述详细讲述 data() 的工作过程,谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2015 年 1 月 12 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

饼状图的拖拽

最后更新于:2022-04-01 20:04:48

本文讲解稍微复杂一些的拖拽应用,即拖拽饼图的各部分。 [![621](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b4178527b05.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/621.png) 在【[入门 - 第 9.1 章](http://www.ourd3js.com/wordpress/?p=190)】讲解了如何制作饼状图。饼状图的各部分是用具有宽度的弧线来表示的。在与用户进行交互的时候,如果每一部分都能拖拽,是很有趣的。 ## 1.饼状图的绘制 与【[入门 - 第 9.1 章](http://www.ourd3js.com/wordpress/?p=190)】稍有有些不同,我们对饼状图的每一个区域都使用一个 g 标签将其包围起来,以便平移操作。 ~~~ var gAll = svg.append("g") .attr("transform","translate("+outerRadius+","+outerRadius+")"); var arcs = gAll.selectAll(".arcs_g") .data(pie(dataset)) .enter() .append("g") .each(function(d){ //指定当前区域的平移量 d.dx = 0; d.dy = 0; }) .call(drag); //调用drag函数 ~~~ 那么在平移的时候,只需要对各部分的 g 使用 transform 即可。在 drag 事件发生时,根据鼠标的参数即可计算出偏移量。上面使用了一个 each() 函数,为每一个区域添加两个变量: dx 和 dy 。用于保存偏移量。 ## 2. drag 事件的定义 每次触发 drag 事件,我们只需要获取鼠标的偏移量,再将其加到原偏移量 dx 和 dy 上即可。 然后再使用 d3.select(this) 选择当前元素,给其应用 transform 即可完成平移操作。 ~~~ var drag = d3.behavior.drag() .origin(function(d) { return d; }) .on("drag", dragmove); function dragmove(d) { d.dx += d3.event.dx; d.dy += d3.event.dy; d3.select(this) .attr("transform","translate("+d.dx+","+d.dy+")"); } ~~~ ## 3. 结果 结果如下,饼图的每一块都可以拖拽: 源代码单击以下链接后查看: [http://www.ourd3js.com/demo/J-6.2/dragpie.html](http://www.ourd3js.com/demo/J-6.2/dragpie.html) 谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2015 年 1 月 6 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

缩放的应用(Zoom)

最后更新于:2022-04-01 20:04:46

缩放(Zoom)是另一种重要的可视化操作,主要是使用鼠标的滚轮进行。 ## 1. zoom 的定义 缩放是由 d3.behavior.zoom() 定义的。 ~~~ var zoom = d3.behavior.zoom() .scaleExtent([1, 10]) .on("zoom", zoomed); function zoomed() { circles_group.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); } ~~~ 第 2 行:scaleExtent 用于设置最小和最大的缩放比例 第 3 行:当 zoom 事件发生时,调用 zoomed 函数 第 5 - 8 行:zoomed 函数,用于更改需要缩放的元素的属性,d3.event.translate 是平移的坐标值,d3.event.scale 是缩放的值。 ## 2. 绘制圆 与【[进阶 - 第 6.0 章](http://www.ourd3js.com/wordpress/?p=714)】一样,绘制两个圆用于测试。只是将圆 circle 元素添加到一个组 g 里,g 元素调用 call(zoom),zoom 为刚才定义的缩放行为。 ~~~ var circles_group = svg.append("g") .call(zoom); circles_group.selectAll("circle") .data(circles) .enter() .append("circle") .attr("cx",function(d){ return d.cx; }) .attr("cy",function(d){ return d.cy; }) .attr("r",function(d){ return d.r; }) .attr("fill","black"); ~~~ ## 3. 结果 结果如下,在圆上滑动鼠标滚轮试试: 源代码单击以下链接后查看: [http://www.ourd3js.com/demo/J-6.1/zoom.html](http://www.ourd3js.com/demo/J-6.1/zoom.html) 谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014 年 12 月 28 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

拖拽的应用(Drag)

最后更新于:2022-04-01 20:04:44

拖拽(Drag)是交互式中很重要的一种,本文将讲解拖拽的使用方法。 ## 1. drag的定义 D3中可用 d3.behavior.drag() 来定义 drag 行为。 ~~~ var drag = d3.behavior.drag() .on("drag", dragmove); function dragmove(d) { d3.select(this) .attr("cx", d.cx = d3.event.x ) .attr("cy", d.cy = d3.event.y ); } ~~~ 第 2 行表示当 drag 事件发生后即调用 dragmove 函数。除了 drag 事件之外,还有 dragstart 和 dragend 事件,这一点在【[进阶 - 第 2.1 章](http://www.ourd3js.com/wordpress/?p=606)】中有过类似的叙述。 dragmove()里,出现了 d3.event.x 和 d3.event.y 两个变量,这是当前鼠标的位置。我们后面将绘制圆,这里的意思是把圆重新绘制到当前鼠标所在处。 ## 2. 绘制圆 绘制圆的方法相信大家都很熟悉了。最后在圆的选择集中使用 call 函数,调用刚才定义的 drag 行为即可。call函数我们前面说过,即将选择集自身作为参数,传递给 drag 函数。 ~~~ var circles = [ { cx: 150, cy:200, r:30 }, { cx: 250, cy:200, r:30 },]; var svg = d3.select("body").append("svg") .attr("width",width) .attr("height",height); svg.selectAll("circle") .data(circles) .enter() .append("circle") .attr("cx",function(d){ return d.cx; }) .attr("cy",function(d){ return d.cy; }) .attr("r",function(d){ return d.r; }) .attr("fill","black") .call(drag); //这里是刚才定义的drag行为 ~~~ ## 3. 结果 结果如下,拖拽试试: 源代码单击以下链接后查看: [http://www.ourd3js.com/demo/J-6.0/drag.html](http://www.ourd3js.com/demo/J-6.0/drag.html) 谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014 年 12 月 27 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

直方图

最后更新于:2022-04-01 20:04:41

直方图用于描述概率分布,D3 提供了直方图的布局 Histogram 用于转换数据。 [![501](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41784c800b.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/12/501.png) 假设有数组 a = [10, 11, 11.5, 12.5, 13, 15, 19, 20 ],现在把10~20的数值范围分为5段,即: 10~12, 12~14, 14~16, 16~18, 18~20 那么数组 a 的各数值都落在这几段区域的哪一部分呢?经过计算,可以知道,这5段分别具有的元素个数为: 3, 2, 1, 0 , 2 将这个用图形展示出来的,就是直方图。好了,开始制作吧~ ## 1. 数据 首先生成随机数据: ~~~ var rand = d3.random.normal(0,25); var dataset = []; for(var i=0;i<100;i++){ dataset.push( rand() ); } ~~~ d3.random.normal 生成一个函数,这个函数能够按正态(高斯)分布随机生成数值。要传入两个参数,第一个是位置参数,第二个是尺寸参数。关于正态分布的定义,可参见[维基百科](http://zh.wikipedia.org/wiki/%E6%AD%A3%E6%80%81%E5%88%86%E5%B8%83)。将这个函数赋值给 rand 之后,接下来只要用 rand() 即可生成随机数。 ## 2. 布局(数据转换) 接下来,要将上述数据进行转换,即确定一个区间和分隔数之后,另数组的数值落在各区域里。先定义一个布局: ~~~ var bin_num = 15; var histogram = d3.layout.histogram() .range([-50,50]) .bins(bin_num) .frequency(true); ~~~ - d3.layout.histogram: 直方图的布局 - range: 区间的范围 - bins: 分隔数 - frequency: 若值为 true,则统计的是个数;若值为 false,则统计的是概率 接下来即可转换数据: ~~~ var data = histogram(dataset); ~~~ 来看看转换前后的数据有什么分别吧。转换前: [![502](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41784dc743.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/12/502.png) 转换后: [![503](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b4178509651.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/12/503.png) 可以看到,转换后的数组,长度即分隔数,每一个区间内有落到此区间的数值(图中的0,1,2,...),数值的个数(length),还有三个参数: - x: 区间的起始位置 - dx: 区间的宽度 - y: 落到此区间的数值的数量(如果 frequency 为 true);落到此区间的概率(如果 frequency 为 false) ## 3. 绘制 绘制之前,需要定义一个比例尺,因为通常我们需要让转换后的 y 在希望的范围内伸缩。 ~~~ var max_height = 400; var rect_step = 30; var heights = []; for(var i=0;i ';

绘制箭头

最后更新于:2022-04-01 20:04:39

在 SVG 绘制区域中作图,在绘制直线和曲线时,常需要在某处添加箭头。本文介绍如何在 D3 中给直线和曲线添加箭头。 [![401](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41784ae7d8.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/12/401.png) 到目前为止,我们绘制 D3 的图表都是在 SVG 绘制区域内,虽然 D3 也可用 Canvas 或 WebGL 等作图,但 SVG 是最常用的。那么,用 D3 来绘制箭头,先要明白在 SVG 中是怎么绘制的。 ## 1. 在 SVG 中定义箭头的标识 定义箭头的标识如下,先写一对 ,里面再写一对 ,其中 marker 的属性的意义为: | viewBox | 坐标系的区域 | |-----|-----| | refX, refY | 在 viewBox 内的基准点,绘制时此点在直线端点上(要注意大小写) | | markerUnits | 标识大小的基准,有两个值:strokeWidth(线的宽度)和userSpaceOnUse(图形最前端的大小) | | markerWidth, markerHeight | 标识的大小 | | orient | 绘制方向,可设定为:auto(自动确认方向)和 角度值 | | id | 标识的id号 | 然后在 marker 里绘制图形即可,下面的代码中用 path 绘制了一个箭头的图形。 ~~~ ~~~ ## 2. 在 SVG 中绘制箭头 有了上面的标识,就可以绘制箭头了。下面绘制一条线段,在线段末尾添加箭头: ~~~ ~~~ 也可以用 path 来绘制: ~~~ ~~~ 在不同的位置绘制的属性如下: - marker-start :路径起点处 - marker-mid:路径中间端点处(必须是 path 中间出现的点) - marker-end :路径终点处 ## 3. 使用 D3 绘制箭头 有了上面的内容,在 D3 中如何绘制呢? 先定义箭头的标识: ~~~ var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var defs = svg.append("defs"); var arrowMarker = defs.append("marker") .attr("id","arrow") .attr("markerUnits","strokeWidth") .attr("markerWidth","12") .attr("markerHeight","12") .attr("viewBox","0 0 12 12") .attr("refX","6") .attr("refY","6") .attr("orient","auto"); var arrow_path = "M2,2 L10,6 L2,10 L6,6 L2,2"; arrowMarker.append("path") .attr("d",arrow_path) .attr("fill","#000"); ~~~ 使用上述 marker 绘制箭头的代码为: ~~~ //绘制直线 var line = svg.append("line") .attr("x1",0) .attr("y1",0) .attr("x2",200) .attr("y2",50) .attr("stroke","red") .attr("stroke-width",2) .attr("marker-end","url(#arrow)"); //绘制曲线 var curve_path = "M20,70 T80,100 T160,80 T200,90"; var curve = svg.append("path") .attr("d",curve_path) .attr("fill","white") .attr("stroke","red") .attr("stroke-width",2) .attr("marker-start","url(#arrow)") .attr("marker-mid","url(#arrow)") .attr("marker-end","url(#arrow)"); ~~~ 结果图为本文开始处的图片,完整代码为: SVG版:[http://www.ourd3js.com/demo/J-4.0/arrow.svg](http://www.ourd3js.com/demo/J-4.0/arrow.svg) D3版:[http://www.ourd3js.com/demo/J-4.0/arrow.html](http://www.ourd3js.com/demo/J-4.0/arrow.html) 谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014 年 12 月 8 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

分区图的函数

最后更新于:2022-04-01 20:04:37

分区图的布局比较简单,本章介绍一下分区图的参数。 分区图布局为: ~~~ d3.layout.partition() ~~~ 其函数有6个。 # nodes() 将根数据传入后,得到的节点的数组,每个节点添加8个参数: - parent - 父节点 - children - 子节点 - value - 表示节点的大小,由下面 value() 函数指定的值,父节点的值等于子节点值的和 - depth - 节点的深度 - x - 节点的x方向的坐标(不一定指x轴方向,跟据 size() 函数的意义而定) - y - 节点的y方向的坐标(同上) - dx - x方向扩展的宽度(同上) - dy - y方向扩展的宽度(同上) # links() 将上述节点数组传入后,得到连接线的关系,起点和终点分别存在 source 和 target 变量中。 # children() 指定表示子节点的字符串。默认是: ~~~ function children(d) { return d.children; } ~~~ 表示在 JSON 文件中,子节点的变量符号用 children 表示: ~~~ { "name":"中国", "children": [ { "name":"浙江" , "children": [ {"name":"杭州" }, {"name":"宁波" }, {"name":"温州" }, {"name":"绍兴" } ] } ] } ~~~ # sort() 指定对同深度的节点进行排序的函数。如果不排序,则按照默认顺序显示。排序函数与JavaScript 相同: ~~~ function comparator(a, b) { return b.value - a.value; } ~~~ 对于以上函数,如果第一个参数应该位于第二个参数之前则需令其返回一个负数,如果相等则返回0,如果第一个参数应该位于第二个之后,则令其返回一个正数。 # value() 设定用哪一个值来表示节点大小。如: ~~~ function value(d) { return d.size; } ~~~ 这样设定的话,用节点里的 size 值来表示节点的大小。 # size() 设置分区图的范围。【[进阶 - 第 3.0 章](#)】和【[进阶 - 第 3.1 章](http://www.ourd3js.com/wordpress/?p=653)】中展示了当 size 函数的设定不同时,图表如何不同。 如果是方形的:size( [ width , height ] ) 如果是圆形的:size( [ 2 * Math.PI, radius * radius ] )      // radius 为圆的半径 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014 年 12 月 7 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

圆形分区图

最后更新于:2022-04-01 20:04:35

分区图布局的 size 函数很有意思,即可用于制作矩形分区图,也可用于制作圆形分区图。本文就来谈讨一下圆形分区图的制作。 [![311](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41784932fc.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/11/311.png) 本文与【[进阶 - 第 3.0 章](http://www.ourd3js.com/wordpress/?p=643)】基本相同,只有布局函数的 size 函数和绘制图形的部分稍有区别。 ## 1. 数据 本文仍然使用【[入门 - 第 9.4 章](http://www.ourd3js.com/wordpress/?p=254)】的数据,内容为中国境内几个城市的所属关系。 ## 2. 布局(数据转换) ~~~ var partition = d3.layout.partition() .sort(null) .size([2 * Math.PI, radius * radius]) .value(function(d) { return 1; }); ~~~ 第 3 行:size 函数,第一个值为 2 * PI ,第二个值为圆半径的平方。如果您只需要得到效果,可不比深究为什么这么做,只需记得这么用即可。 注意第3行与【[进阶 - 第 3.0 章](http://www.ourd3js.com/wordpress/?p=643)】的不同。 ## 3. 绘制 先定义一个绘制弧形的函数,这个函数在【[入门 - 第 9.1 章](http://www.ourd3js.com/wordpress/?p=190)】中也用过。 ~~~ var arc = d3.svg.arc() .startAngle(function(d) { return d.x; }) .endAngle(function(d) { return d.x + d.dx; }) .innerRadius(function(d) { return Math.sqrt(d.y); }) .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); }); ~~~ 请好好体会上面的代码是什么意思。如果以圆形的形式来转换数据,那么 d.x 和 d.y 分别代表圆弧的绕圆心方向的起始位置和由圆心向外方向的其实位置。d.dx 和 d.dy 分别代表各自的宽度。 接下来分别绘制圆弧和文字。 ~~~ var arcs = svg.selectAll("g") .data(nodes) .enter().append("g"); arcs.append("path") .attr("display", function(d) { return d.depth ? null : "none"; }) // hide inner ring .attr("d", arc) .style("stroke", "#fff") .style("fill", function(d) { return color((d.children ? d : d.parent).name); }) .on("mouseover",function(d){ d3.select(this) .style("fill","yellow"); }) .on("mouseout",function(d){ d3.select(this) .transition() .duration(200) .style("fill", function(d) { return color((d.children ? d : d.parent).name); }); }); arcs.append("text") .style("font-size", "12px") .style("font-family", "simsun") .attr("text-anchor","middle") .attr("transform",function(d,i){ //第一个元素(最中间的),只平移不旋转 if( i == 0 ) return "translate(" + arc.centroid(d) + ")"; //其他的元素,既平移也旋转 var r = 0; if( (d.x+d.dx/2)/Math.PI*180 < 180 ) // 0 - 180 度以内的 r = 180 * ((d.x + d.dx / 2 - Math.PI / 2) / Math.PI); else // 180 - 360 度以内的 r = 180 * ((d.x + d.dx / 2 + Math.PI / 2) / Math.PI); //既平移也旋转 return "translate(" + arc.centroid(d) + ")" + "rotate(" + r + ")"; }) .text(function(d) { return d.name; }); ~~~ 绘制方法问题不大,唯一要注意的是文字的旋转角度问题,请好好看看上面的注释问题。 ## 4. 结果 完整代码,请点击下面的链接,再右键点击查看源代码: [http://www.ourd3js.com/demo/J-3.1/circle_partition.html](http://www.ourd3js.com/demo/J-3.1/circle_partition.html) ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014 年 11 月 30 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

分区图

最后更新于:2022-04-01 20:04:32

分区图( Partition ),也是 D3 的一个布局( Layout )。这个布局很有意思,可以做成方形也可能做成圆形,本文先介绍方形分区图的制作方法,这也是分区图最基本的形式。 [![301](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417845ed28.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/11/301.png) 分区图也是用于表示包含与被包含关系的。 ## 1. 数据 本文使用【[入门 - 第 9.4 章](http://www.ourd3js.com/wordpress/?p=254)】的数据,内容为中国境内几个城市的所属关系。 ## 2. 布局(数据转换) ~~~ var partition = d3.layout.partition() .sort(null) .size([width,height]) .value(function(d) { return 1; }); ~~~ 第 1 行:分区图的布局。 第 2 行:sort 设定内部的顶点的排序函数,null 表示不排序。 第 3 行:size 设定转换后图形的范围,这个值很重要,运用得当可变为圆形分区图。 第 4 行:value 设定表示分区大小的值。这里的意思是:如果数据文件中用 size 值表示结点大小,那么这里可写成 return d.size。 接下来读取并转换数据,代码如下: ~~~ d3.json("city_tree.json", function(error, root) { if(error) console.log(error); console.log(root); //转换数据 var nodes = partition.nodes(root); var links = partition.nodes(nodes); //输出转换后的顶点 console.log(nodes); } ~~~ 来看看转换后的数据为何: [![302](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417847709c.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/11/302.png) 顶点中增加了几个变量,其中: - x: 顶点的 x 坐标位置 - y: 顶点的 y 坐标位置 - dx: 顶点的宽度 dx - dy: 顶点的高度 dy ## 3. 绘制 绑定顶点数据,分别绘制矩形和文字,代码如下: ~~~ var rects = svg.selectAll("g") .data(nodes) .enter().append("g"); rects.append("rect") .attr("x", function(d) { return d.x; }) // 顶点的 x 坐标 .attr("y", function(d) { return d.y; }) // 顶点的 y 坐标 .attr("width", function(d) { return d.dx; }) // 顶点的宽度 dx .attr("height", function(d) { return d.dy; }) //顶点的高度 dy .style("stroke", "#fff") .style("fill", function(d) { return color((d.children ? d : d.parent).name); }) .on("mouseover",function(d){ d3.select(this) .style("fill","yellow"); }) .on("mouseout",function(d){ d3.select(this) .transition() .duration(200) .style("fill", function(d) { return color((d.children ? d : d.parent).name); }); }); rects.append("text") .attr("class","node_text") .attr("transform",function(d,i){ return "translate(" + (d.x+20) + "," + (d.y+20) + ")"; }) .text(function(d,i) { return d.name; }); ~~~ 注意上面的注释处,好好体会转换后的数据是怎么运用的。 ## 4. 结果 完整代码,请点击下面的链接,再右键点击查看源代码: [http://www.ourd3js.com/demo/J-3.0/rect_partition.html](http://www.ourd3js.com/demo/J-3.0/rect_partition.html) ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014 年 11 月 23 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

力学图的参数

最后更新于:2022-04-01 20:04:30

力学图的布局中有很多参数,本文将逐个说明。 D3 中的力学图布局是使用[韦尔莱积分法](http://zh.wikipedia.org/wiki/%E9%9F%A6%E5%B0%94%E8%8E%B1%E7%A7%AF%E5%88%86%E6%B3%95)计算的,这是一种用于求解牛顿运动方程的数值方法,被广泛应用于分子动力学模拟以及视频游戏中。定义布局的代码如下: ~~~ var force = d3.layout.force() ~~~ 即可,D3 中提供了 17 个函数用于设定其参数和事件,在所有布局中是最多的,下面将对其进行说明。 ## size() 用于设定力学图的作用范围,使用方法为 force.size( [ x , y ] ),这个函数用于指定两件事: - 重力的重心位置为 ( x/2 , y/2 ) - 所有节点的初始位置限定为 [ 0 , x ] 和 [ 0 , y ] 之间(但并非之后也是如此) 如果不指定,默认为 [ 1 , 1 ] 。 ## linkDistance() 指定结点连接线的距离,默认为20。如果距离是一个常数,那么各连接线的长度总是固定的;如果是一个函数,那么这个函数是作用于各连接线( source , target )的。 ## linkStrength() 指定连接线的坚硬度,值的范围为[ 0 , 1 ],值越大越坚硬。其直观感受是: - 值为1,则拖动一个顶点A,与之相连的顶点会与A保持linkDistance设定的距离运动 - 值为0,则拖动一个顶点A,与之相连的顶点不会运动,连接线会被拉长 ## friction() 定义摩擦系数的函数,值的范围为[ 0 , 1 ],默认为0.9。但是这个值其实并非物理意义上的摩擦,其实其意义更接近速度随时间产生的损耗,这个损耗是针对每一个顶点的。 - 值为1,则没有速度的损耗。 - 值为0,则速度的损耗最大。 ##charge() 设定引力,是排斥还是吸引,默认值为-30。 - 值为+,则相互吸引,绝对值越大吸引力越大。 - 值为-,则相互排斥,绝对值越大排斥力越大。 ## chargeDistance() 设定引力的作用距离,超过这个距离,则没有引力的作用。默认值为无穷大。 ## gravity() 以 size 函数设定的中心产生重力,各顶点都会向中心运动,默认值为0.1。也可以设定为0,则没有重力的作用。 ## theta() 顶点数如果过多,计算的时间就会加大(O(n log n))。theta 就是为了限制这个计算而存在的,默认值为0.8。这个值越小,就能把计算限制得越紧。 ## alpha() 设定动画运动的时间,超过时间后运动就会停止。其实 - force.start() 即 alpha(0.1) - force.stop() 即 alpha(0) 谢谢阅读。 ### 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014 年 11 月 15 日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢
';

力学图的事件 + 顶点的固定

最后更新于:2022-04-01 20:04:28

本章讨论在力学图中常用到的事件( Event ),然后对【[进阶 - 第 2.0 章](http://www.ourd3js.com/wordpress/?p=555)】的人物关系图进行改进,使用户能够固定拖拽的对象。 在【[入门 - 第 9.2 章](http://www.ourd3js.com/wordpress/?p=196)】和【[进阶 - 第 2.0 章](http://www.ourd3js.com/wordpress/?p=555)】中,都用到了以下代码: ~~~ force.on("tick", function(){ }); ~~~ 这里的 force 是之前代码中定义的布局( Layout ),tick 表示当运动进行中每更新一帧时。这是力学图中最常使用的事件,用于设定力学图每一帧是如何更新的。除此之外,还有一些其他常用的事件。 ## 1. 布局的事件 代码中,假设定义如下的布局: ~~~ var force = d3.layout.force() .size([width,height]) .linkDistance(200) .charge(-1500); ~~~ 力学图布局 force 本身的事件,D3 提供了3个,分别为 start ,end,tick。在写代码时,可形如: ~~~ //力学图运动开始时 force.on("start", function(){ console.log("开始"); }); //力学图运动结束时 force.on("end", function(){ console.log("结束"); }); //力学图每一帧 force.on("tick", function(){ console.log("进行中"); }); ~~~ 各事件发生时,就会执行相应的代码。 ## 2. 拖拽的事件 在【[入门 - 第 9.2 章](http://www.ourd3js.com/wordpress/?p=196)】和【[进阶 - 第 2.0 章](http://www.ourd3js.com/wordpress/?p=555)】中,都出现了以下代码: ~~~ .call(force.drag); ~~~ 即设定当拖拽时调用函数 force.drag()。D3 中提供了3种拖拽事件:dragstart、dragend、drag。 ~~~ var drag = force.drag() .on("dragstart",function(d,i){ console.log("拖拽状态:开始"); }) .on("dragend",function(d,i){ console.log("拖拽状态:结束"); }) .on("drag",function(d,i){ console.log("拖拽状态:进行中"); }); ~~~ 上面代码中,分别定义了三种事件后,将此拖拽函数赋值给变量 drag,在调用时,只要使用: ~~~ .call(drag); ~~~ 即可。 ## 3. 顶点的固定 使用布局转换数据之后,顶点有一个属性 fixed 。当这个值为 true 时,顶点就是固定不动的;为 false 时,它就是运动的。默认是 false 的。如果要改进【[进阶 - 第 2.0 章](http://www.ourd3js.com/wordpress/?p=555)】的代码,使得用户能够任意固定和解锁顶点,可添加代码如下:当拖拽开始时,被拖拽顶点设定为固定的: ~~~ var drag = force.drag() .on("dragstart",function(d,i){ d.fixed = true; //拖拽开始后设定被拖拽对象为固定 label_text_2.text("拖拽状态:开始"); }) ~~~ 当鼠标双击顶点时,对顶点解锁: ~~~ nodes_img.on("dblclick",function(d,i){ d.fixed = false; }) ~~~ ## 4. 结果 在左上角添加了标签文字,请好好体会一下各事件发生的状况。 拖拽后顶点会固定,双击顶点能够解锁。 完整代码请点击下面链接,右键选择“查看网页源代码”: [http://www.ourd3js.com/demo/J-2.1/relationforce.html](http://www.ourd3js.com/demo/J-2.1/relationforce.html) 谢谢阅读。 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014年11月08日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:转载请注明出处,谢谢
';

力学图 + 人物关系图

最后更新于:2022-04-01 20:04:26

力学图(力导向图)与生活中常见的人物关系图结合,是比较有趣的。本文将以此为凭,阐述在力学图中如何插入外部图片和文字。 在【[第 9.2 章](http://www.ourd3js.com/wordpress/?p=196)】中制作了一个最简单的力学图。其后有很多朋友有疑问,主要的问题包括: - 如何在小球旁插入文字 - 如何将小球换为别的图形 - 如何插入图片 - 如何限制小球运动的边界 本文将对以上问题依次做出解说。其中前三点是 SVG 元素的问题,和 D3 无多大关联。 ## 1. SVG 图片 SVG 的图片元素的详细解说可看【[官方文档-图片](http://www.w3.org/TR/SVG11/struct.html#ImageElement)】。通常,我们只需要使用到图片元素的五个属性就够了。 ~~~ ~~~ 其中: - xlink:href - 图片名称或图片网址 - x - 图片坐上角 x 坐标 - y - 图片坐上角 y 坐标 - width - 图片宽度 - height- 图片高度 在 D3 中插入图片,代码形如: ~~~ svg.selectAll("image") .data(dataset) .enter() .append("image") .attr("x",200) .attr("y",200) .attr("width",100) .attr("height",100) .attr("xlink:href","image.png"); ~~~ ## 2. SVG 文本 SVG 的文本元素和图片类似,详细属性见【[官方文档-文本](http://www.w3.org/TR/SVG11/text.html#TextElement)】。 ~~~ Hello ~~~ 其中: - x - 文本 x 坐标 - y - 文本 y 坐标 - dx- x 轴方向的文本平移量 - dy- y 轴方向的文本平移量 - font-family - 字体 - font-size - 字体大小 - fill - 字体颜色 在 D3 中插入文本,代码形如: ~~~ svg.selectAll("text") .data(dataset) .enter() .append("text") .attr("x",250) .attr("y",150) .attr("dx",10) .attr("dy",10) .text("Hello"); ~~~ ## 3. 源文件 接下来制作力学图的源文件,本次将数据写入 JSON 文件中。 呵呵,借用一下【仙剑4】的人物,本人也是个仙剑迷,期待15年7月【仙剑6】的上市。 ~~~ { "nodes":[ { "name": "云天河" , "image" : "tianhe.png" }, { "name": "韩菱纱" , "image" : "lingsha.png" }, { "name": "柳梦璃" , "image" : "mengli.png" }, { "name": "慕容紫英" , "image" : "ziying.png" } ], "edges":[ { "source": 0 , "target": 1 , "relation":"挚友" }, { "source": 0 , "target": 2 , "relation":"挚友" }, { "source": 0 , "target": 3 , "relation":"挚友" } ] } ~~~ 如上,在 JSON 文件中添加数据,再将图片文件与 JSON 文件放于同一目录下即可(放哪都行,最主要是看程序中是如何实现的)。 ## 4. 力学图 ### 4.1 读入文件 读入 JSON 文件,这点应该很熟了吧。不然可以先看看【[第 9.4 章](http://www.ourd3js.com/wordpress/?p=245)】。 ~~~ d3.json("relation.json",function(error,root){ if( error ){ return console.log(error); } console.log(root); } ~~~ ### 4.2 定义力学图的布局 力学图的 Layout(布局)如下: ~~~ var force = d3.layout.force() .nodes(root.nodes) .links(root.edges) .size([width,height]) .linkDistance(200) .charge(-1500) .start(); ~~~ 其中 linkDistance 是结点间的距离, charge 是定义结点间是吸引(值为正)还是互斥(值为负),值越大力越强。 ### 4.3 绘制连接线 绘制结点之间的连接线的代码如下: ~~~ var edges_line = svg.selectAll("line") .data(root.edges) .enter() .append("line") .style("stroke","#ccc") .style("stroke-width",1); var edges_text = svg.selectAll(".linetext") .data(root.edges) .enter() .append("text") .attr("class","linetext") .text(function(d){ return d.relation; }); ~~~ 其中,第 1 - 6 行:绘制直线 第 8 - 15 行:绘制直线上的文字 直线上文字的样式为: ~~~ .linetext { font-size: 12px ; font-family: SimSun; fill:#0000FF; fill-opacity:0.0; } ~~~ fill-opacity 是透明度,0表示完全透明,1表示完全不透明。这里是0,表示初始状态下不显示。 ### 4.4 绘制结点 绘制结点的图片和文字: ~~~ var nodes_img = svg.selectAll("image") .data(root.nodes) .enter() .append("image") .attr("width",img_w) .attr("height",img_h) .attr("xlink:href",function(d){ return d.image; }) .on("mouseover",function(d,i){ d.show = true; }) .on("mouseout",function(d,i){ d.show = false; }) .call(force.drag); var text_dx = -20; var text_dy = 20; var nodes_text = svg.selectAll(".nodetext") .data(root.nodes) .enter() .append("text") .attr("class","nodetext") .attr("dx",text_dx) .attr("dy",text_dy) .text(function(d){ return d.name; }); ~~~ 第 1 - 16 行:绘制图片 第 10 - 15 行:当鼠标移到图片上时,显示与此结点想关联的连接线上的文字。在这里只是对 d.show 进行布尔型赋值,在后面更新时会用到这个值。 第 21 - 30 行:绘制图片下方的文字 ### 4.5 更新 让力学图不断更新,使用 force.on("tick",function(){ }),表示每一步更新都调用 function 函数。 ~~~ force.on("tick", function(){ //限制结点的边界 root.nodes.forEach(function(d,i){ d.x = d.x - img_w/2 < 0 ? img_w/2 : d.x ; d.x = d.x + img_w/2 > width ? width - img_w/2 : d.x ; d.y = d.y - img_h/2 < 0 ? img_h/2 : d.y ; d.y = d.y + img_h/2 + text_dy > height ? height - img_h/2 - text_dy : d.y ; }); //更新连接线的位置 edges_line.attr("x1",function(d){ return d.source.x; }); edges_line.attr("y1",function(d){ return d.source.y; }); edges_line.attr("x2",function(d){ return d.target.x; }); edges_line.attr("y2",function(d){ return d.target.y; }); //更新连接线上文字的位置 edges_text.attr("x",function(d){ return (d.source.x + d.target.x) / 2 ; }); edges_text.attr("y",function(d){ return (d.source.y + d.target.y) / 2 ; }); //是否绘制连接线上的文字 edges_text.style("fill-opacity",function(d){ return d.source.show || d.target.show ? 1.0 : 0.0 ; }); //更新结点图片和文字 nodes_img.attr("x",function(d){ return d.x - img_w/2; }); nodes_img.attr("y",function(d){ return d.y - img_h/2; }); nodes_text.attr("x",function(d){ return d.x }); nodes_text.attr("y",function(d){ return d.y + img_w/2; }); }); ~~~ ## 5. 结果 结果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b417842fd80.jpg) 可点击下面的地址,右键点浏览器查看完整代码:[http://www.ourd3js.com/demo/J-2.0/relationforce.html](http://www.ourd3js.com/demo/J-2.0/relationforce.html) ## 6. 结束语 在【[入门系列](http://www.ourd3js.com/wordpress/?p=396)】中,疑问最多的是【[树状图](http://www.ourd3js.com/wordpress/?p=254)】,本想先解决这个问题的,但是由于我也有些问题还没想明白,所以先写本文这个较容易的。接下来还将有几篇关于力学图的,树状图的整理要稍微拖一段时间。 谢谢阅读。 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014年10月25日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和[CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:转载请注明出处,谢谢
';

读取 CSV 文件时乱码的解决方法

最后更新于:2022-04-01 20:04:23

在 D3 中使用 d3.csv 读取 CSV 文件时,有时会出现乱码问题。怎么解决呢? ## 1. 乱码问题 使用 d3.csv 读取 xxx.csv 文件时,如果 xxx.csv 文件使用的是 UTF-8 编码,不会有什么问题。当然,个人认为尽量使用 UTF-8 编码,可以在同一编码内使用各国文字。 但是,如果 xxx.csv 文件使用的是 utf-8 编码,使用 Microsoft Excel 打开的时候,可能会出现乱码,因为国内的 Excel 默认使用 GB2312 打开,而且在打开的时候不能选择编码( OpenOffice 没有这个问题 )。当然,在 Excel 中也是有方法可以用 utf-8 编码打开的。具体的方法可以到网上去查。 GB2312 和 GB18030 等是国内常用的编码,如果 CSV 文件用这两种编码保存,那么用 Excel 可直接打开而不出现乱码。但是,如果用了,用 d3.csv 读取的时候,又会在可视化的时候出现乱码,这正是问题所在。 ## 2. 解决方法 解决方法很简单,但是如果不知道的话,是很费心的。 一言以蔽之,解决方法需要: 在 D3 中能够手动设定用什么编码读取文件。 在 【[进阶系列 1.0](http://www.ourd3js.com/wordpress/?p=430)】 和 【[进阶系列 1.1](http://www.ourd3js.com/wordpress/?p=501)】中,使用了 d3.csv 和 d3.tsv 两个函数,也提到了,它们的区别仅仅是分隔符不同。也提到了,它们实质上都是 d3.dsv 函数,即: ~~~ d3.csv = d3.dsv(",", "text/csv"); d3.tsv = d3.dsv(" ", "text/tab-separated-values"); ~~~ 在 d3.dsv 的第二的参数中,其实可以添加编码的,形如: ~~~ var csv = d3.dsv(",", "text/csv;charset=gb2312"); var tsv = d3.dsv(" ", "text/tab-separated-values;charset=gb2312"); ~~~ 如此,你可以定义自己的 csv 和 tsv 读取函数,编码如上添加即可。使用方法形如: ~~~ csv("xxx.csv",function(error,csvdata){ } tsv("xxx.tsv",function(error,tsvdata){ } ~~~ 如此,乱码的问题即可解决。谢谢阅读。 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014年10月18日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和[CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:转载请注明出处,谢谢
';

其他表格文件的读取

最后更新于:2022-04-01 20:04:21

CSV 表格文件是以逗号作为单元分隔符的,其他还有以制表符 Tab 作为单元分隔符的 TSV 文件,还有人为定义的其它分隔符的表格文件。本文将说明在 D3 中如何读取它们。 ## 1. TSV 表格文件是什么 TSV(Tab Separated Values),制表分隔值,它和 CSV 文件仅仅是分隔符不一致。它的格式如下: ~~~ name age 张三 22 李四 24 ~~~ ## 2. D3 中读取 TSV 文件 在 D3 中读取 TSV 文件的方法和 CSV 文件是一样的,只要更改一下函数名即可。方法如下: ~~~ d3.tsv("table.tsv",function(error,tsvdata){ console.log(tsvdata); var str = d3.tsv.format( tsvdata ); console.log(str.length); console.log(str); }); ~~~ 我们可以看到,这和[【进阶系列 — 1.0】](http://www.ourd3js.com/wordpress/?p=430)是基本一样的,详细说明可参见此文。 ## 3. D3 中读取 CSV 和 TSV 的本质 在上面两节我们可以看到,读取 CSV 和 TSV 惊人地相似。其实它们本质上都是一个函数,我们来看看 D3 源码中的定义: ~~~ d3.csv = d3.dsv(",", "text/csv"); d3.tsv = d3.dsv(" ", "text/tab-separated-values"); ~~~ 可以看到,它们其实都是 d3.dsv 函数。那么这个 dsv 函数是怎么回事呢?dsv 其实可以读取以任意字符或字符串作为分隔符的表格文件。接下来我们来试试用 dsv 函数读取以分号作为分隔符的表格文件。假设有如下文件: ~~~ name;age 张三;22 李四;24 ~~~ 读取的代码如下: ~~~ var dsv = d3.dsv(";", "text/plain"); dsv("table.dsv",function(error,dsvdata){ if(error) console.log(error); console.log(dsvdata); }); ~~~ 先用 d3.dsv(";", "text/plain"); 定义分隔符为分号,再按照读取 csv 和 tsv 文件一样的方法读取即可。但要注意第二行不再需要用 d3.dsv ,因为变量 dsv 已经是一个函数了。 ## 4. 结束语 CSV 文件和 TSV 文件仅仅是分隔符不同,它们的本质都是调用的 DSV 函数,所以 DSV 函数的掌握至关重要。 谢谢阅读。 文档信息 - 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND) - 发表日期:2014年10月03日 - 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和[CSDN个人博客](http://blog.csdn.net/lzhlzz) - 备注:转载请注明出处,谢谢
';

CSV 表格文件的读取

最后更新于:2022-04-01 20:04:19

在入门系列的教程中,我们常用 d3.json() 函数来读取 json 格式的文件。json 格式很强大,但对于普通用户可能不太适合,普通用户更喜欢的是用 Microsoft Excel 或 OpenOffice Calc 等生成的表格文件,因为简单易懂,容易编辑。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b4174789bc8.png) Microsoft Excel 通常会保存为 xls 格式, OpenOffice Calc 通常会保存为 ods 格式。这些格式作为表格文件来说都很强大,但要读取它们是有些麻烦的,D3 中也没有提供这样的方法。但是表格软件都会支持生成csv 格式,它是一种非常基本的、通用的、简单的表格文件。本文将会说明在 D3 中怎么读取和使用 csv 文件。 ## 1. CSV 格式是什么 CSV(Comma Separated Values),逗号分隔值,它是以纯文本形式存储表格数据的,每个单元格之间用逗号(Comma)分隔。CSV格式没有一个通用标准,通常使用的是[RFC 4180](http://tools.ietf.org/html/rfc4180) 中所示的描述。 CSV 的文本格式如下: ~~~ 省份,人口,GDP 山东,9000,50000 浙江,5000,20000 ~~~ 理解起来非常简单,每一个单元格之间用逗号隔开。如果想在单元格里输入逗号怎么办呢?用双引号框起来就行,如下: ~~~ 省份,人口,GDP 山东,"9,000","50,000" 浙江,"5,000","20,000" ~~~ 有些软件在保存CSV格式时,会让你选择使用什么符号(逗号、分号等)来分隔单元格,尽量选择逗号吧。 ## 2. 在 OpenOffice 中编辑和保存 CSV 文件 Microsoft Excel 虽然强大却是收费的,近几年我已不使用。 OpenOffice 不仅开源免费,而且功能同样强大。下面来说一下用 OpenOffice 怎么编辑和保存为 CSV 文件,当然一般自己摸索着也能会用,非常简单。 (1) 首先,打开 OpenOffice Calc 。就像 Microsoft Office 中有 Word、Excel、PowerPoint 一样,OpenOffice 中编辑表示使用的是 Calc 。打开之后,像正常一样输入单元格的内容,假设输入如下: [![101](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41747a3c85.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/10/101.png) (2)点击“文件”,“另存为”。文件类型选择 “CSV 文本”,底下再勾选上“编辑筛选设置”。 [![102](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41747ba953.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/10/102.png) (3) 弹出的对话框中,选择编码(建议用 UTF8),字段分隔符选择"逗号",文本分隔符选择“分号”。点击“确定”。 [![103](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41747d112c.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/10/103.png) (4) 保存成功后,用记事本打开,结果如下: [![104](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b41747f2abd.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/10/104.png) 在 D3.js 中,读取 CSV 文件的函数只支持用逗号分隔单元格,所以请务必这样保存。 ## 3. 在 D3.js 中读取 CSV 文件 在 D3.js 中提供了 d3.csv() 函数来读取 CSV 文件。函数 API 可参见: [https://github.com/mbostock/d3/wiki/CSV](https://github.com/mbostock/d3/wiki/CSV) 。 用它读取文件的代码如下: ~~~ d3.csv("table.csv",function(error,csvdata){ if(error){ console.log(error); } console.log(csvdata); }); ~~~ 这段代码是读取了 table.csv 文件后,再输出读到的数据。输出如下: [![105](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b4178411276.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2014/10/105.png) 我们可以看到,变量中 csvdata 是保存了一个数组,数组中的每个元素都一个对象,每个对象里都有 age 、name、sex 三个成员变量。这三个成员变量正是所编辑的表格的头一排的三个单元格。如此,我们就可以在代码中这样调用了。 ~~~ for( var i=0; i ';