首页IT科技d3js和threejs(D3.js基础教程)

d3js和threejs(D3.js基础教程)

时间2025-07-17 07:19:10分类IT科技浏览5305
导读:D3: Data-Driven Documents...

D3: Data-Driven Documents

D3 (或D3.js)是一个JavaScript库              ,用于使用Web标准可视化数据              。 D3帮助您使用SVG                    ,Canvas和HTML使数据栩栩如生                    。 D3将强大的可视化和交互技术与数据驱动的DOM操作方法相结合        ,为您提供现代浏览器的全部功能           ,并为您的数据设计正确的可视界面提供了自由        。

官方资源

API Reference Release Notes Gallery Examples Wiki

安装D3

npm安装

安装命令npm install d3;

导入D3到ES2015应用中                   ,或者导入D3中一个模块使用            ,范例如下:

import {scaleLinear} from "d3-scale";

导入D3所有模块:

import * as d3 from "d3";

在Node环境中使用:

var d3 = require("d3");

自定义导入D3模块组合:

var d3 = Object.assign({}, require("d3-format"), require("d3-geo"), require("d3-geo-projection")); 直接下载D3包

请下载最新版本,发行的 release包支持anonymous AMD, CommonJS, and vanilla环境           。你也可以直接从d3js.org, CDNJS, or unpkg上下载        ,例如:

<script src="https://d3js.org/d3.v5.js"></script>

引用压缩版本:

<script src="https://d3js.org/d3.v5.min.js"></script>

也可以直接引用其中的一个微库                   ,例如: d3-selection:

<script src="https://d3js.org/d3-selection.v1.js"></script>

D3的优点

前端可视化库中               ,Hightcharts(商业付费)              、Echarts                    、Charts可以看作一类    ,能够非常简单的制作图表                    ,但是给予开发者控制和设计的空间少                  ,封装层次太高,会失去部分自由                 ,太低又会使程序太长                     ,D3取得了相对完美的平衡:

1)D3相对比较底层    ,代码却足够简洁;

2)D3更像数学库              ,为绘图提供了支持;

3)封装了很多操作                    ,又给予了足够的自由;

如何使用D3来绘图

0        、D3的学习方法

D3是一个JS库        ,api非常多           ,也很完善                   ,尤其是            ,出版物都非常完善        ,示例很多                   ,只需要看相关示例               ,会查API文档即可                   。下面拿几个D3基本的使用来介绍下D3的运用            。

1           、选择元素和绑定数据

如何选择元素

在 D3 中    ,用于选择元素的函数有两个:

d3.select():是选择所有指定元素的第一个 d3.selectAll():是选择指定元素的全部

这两个函数返回的结果称为选择集        。

例如                    ,选择集的常见用法如下:

var body = d3.select("body"); //选择文档中的body元素 var svg = body.select("svg"); //选择body中的svg元素 var p = body.selectAll("p"); //选择body中所有的p元素 var p1 = body.select("p"); //选择body中第一个p元素 var rects = svg.selectAll("rect"); //选择svg中所有的rect元素

假设在 body 中有三个段落元素:

<p>Apple</p> <p>Pear</p> <p>Banana</p>

现在                  ,要分别完成以下四种选择元素的任务                   。

选择第一个 p 元素

使用 select ,参数传入 p 即可                 ,如此返回的是第一个 p 元素               。

var body = d3.select("body"); var p1 = body.select("p"); p1.style("color","red"); // 将第一p元素内容置为红色 选择所有 p 元素

使用 selectAll 选择 body 中所有的 p 元素    。

var body = d3.select("body"); var p = body.selectAll("p"); p.style("color", "red"); 根据id选择元素

使用 select 选择元素                     ,注意参数中 id 名称前要加 # 号                    。该方法可用于选择任何位置的元素    ,示例如下:

<p>Apple</p> <p id="pear-id">Pear</p> <p>Banana</p> <script> var body = d3.select("body"); var p2 = body.select("#pear-id"); p2.style("color", "red"); </script> 选择后两个 p 元素

给后两个元素添加 class              ,

<p class="myclass">Pear</p> <p class="myclass">Banana</p>

由于需要选择多个元素                    ,要用 selectAll                  。注意参数        ,class 名称前要加一个点。

var p = body.selectAll(".myclass"); p.style("color","red");

关于 select 和 selectAll 的参数           ,其实是符合 CSS 选择器的条件的                   ,即用“井号(#)              ”表示 id            ,用“点(.)                      ”表示 class                 。

此外        ,对于已经绑定了数据的选择集                   ,还有一种选择元素的方法               ,那就是灵活运用 function(d, i)                     。我们已经知道参数 i 是代表索引号的    ,于是便可以用条件判定语句来指定执行的元素    。

如何绑定数据

D3 中是通过以下两个函数来绑定数据的:

datum():绑定一个数据到选择集上 data():绑定一个数组到选择集上                    ,数组的各项值分别与选择集的各元素绑定

相对而言                  ,data() 比较常用              。

假设现在有三个段落元素如下:

<p>Apple</p> <p>Pear</p> <p>Banana</p> datum()

作用是绑定一个数据到选择集上                    。

假设有一字符串 World,要将此字符串分别与三个段落元素绑定                 ,代码如下:

var str = "World"; var body = d3.select("body"); var p = body.selectAll("p"); p.datum(str); p.text(function(d, i){ return "第 "+ i + " 个元素绑定的数据是 " + d; });

绑定数据后                     ,使用此数据来修改三个段落元素的内容    ,其结果如下:

第 0 个元素绑定的数据是 World 第 1 个元素绑定的数据是 World 第 2 个元素绑定的数据是 World

在上面的代码中              ,用到了一个无名函数 function(d, i)        。当选择集需要使用被绑定的数据时                    ,常需要这么使用           。其包含两个参数        ,其中:

d 代表数据           ,也就是与某元素绑定的数据                   。 i 代表索引                   ,代表数据的索引号            ,从 0 开始            。

例如        ,上述例子中:第 0 个元素 apple 绑定的数据是 World        。

data()

有一个数组                   ,接下来要分别将数组的各元素绑定到三个段落元素上                   。

var dataset = ["I like dog","I like cat","I like snake"];

绑定之后               ,其对应关系的要求为:

Apple 与 I like dog 绑定 Pear 与 I like cat 绑定 Banana 与 I like snake 绑定

调用 data() 绑定数据    ,并替换三个段落元素的字符串为被绑定的字符串                    ,代码如下:

var body = d3.select("body"); var p = body.selectAll("p"); p.data(dataset) .text(function(d, i){ return d; });

这段代码也用到了一个无名函数 function(d, i)                  ,其对应的情况如下:

当 i == 0 时, d 为 I like dog               。 当 i == 1 时                 , d 为 I like cat    。 当 i == 2 时                     , d 为 I like snake                    。

此时    ,三个段落元素与数组 dataset 的三个字符串是一一对应的              ,因此                    ,在函数 function(d, i) 直接 return d 即可                  。

结果自然是三个段落的文字分别变成了数组的三个字符串。

I like dog I like cat I like snake

2                   、插入            、删除元素

插入元素

插入元素涉及的函数有两个:

append():在选择集末尾插入元素 insert():在选择集前面插入元素

假设有三个段落元素        ,与上文相同                 。

append() body.append("p") .text("append p element");

在 body 的末尾添加一个 p 元素           ,结果为:

Apple Pear Banana append p element insert()

在 body 中 id 为 myid 的元素前添加一个段落元素                     。

body.insert("p","#pear-id") .text("insert p element");

已经指定了 Pear 段落的 id 为 myid                   ,因此结果如下    。

Apple insert p element Pear Banana 删除元素

删除一个元素时            ,对于选择的元素        ,使用 remove 即可                   ,例如:

var p = body.select("#pear-id"); p.remove();

如此即可删除指定 id 的段落元素              。

3        、做一个简单的图表

柱形图是一种最简单的可视化图标               ,主要有矩形                   、文字标签               、坐标轴组成                    。本文为简单起见    ,只绘制矩形的部分                    ,用以讲解如何使用 D3 在 SVG 画布中绘图        。

画布是什么

前几章的处理对象都是 HTML 的文字                  ,没有涉及图形的制作           。

要绘图,首要需要的是一块绘图的“画布      ”                   。

HTML 5 提供两种强有力的“画布          ”:SVGCanvas            。

SVG 是什么

SVG                 ,指可缩放矢量图形(Scalable Vector Graphics)                     ,是用于描述二维矢量图形的一种图形格式    ,是由万维网联盟制定的开放标准        。 SVG 使用 XML 格式来定义图形              ,除了 IE8 之前的版本外                    ,绝大部分浏览器都支持 SVG        ,可将 SVG 文本直接嵌入 HTML 中显示                   。

SVG 有如下特点:

SVG 绘制的是矢量图           ,因此对图像进行放大不会失真               。 基于 XML                   ,可以为每个元素添加 JavaScript 事件处理器    。 每个图形均视为对象            ,更改对象的属性        ,图形也会改变                    。 不适合游戏应用                  。 Canvas 是什么

Canvas 是通过 JavaScript 来绘制 2D 图形                   ,是 HTML 5 中新增的元素。

Canvas 有如下特点:

绘制的是位图               ,图像放大后会失真                 。 不支持事件处理器                     。 能够以 .png 或 .jpg 格式保存图像 适合游戏应用(是逐像素进行渲染的) 添加画布

D3 虽然没有明文规定一定要在 SVG 中绘图    ,但是 D3 提供了众多的 SVG 图形的生成器                    ,它们都是只支持 SVG 的    。因此                  ,建议使用 SVG 画布              。

使用 D3 在 body 元素中添加 svg 的代码如下:

var width = 300; //画布的宽度 var height = 300; //画布的高度 var svg = d3.select("body") //选择文档中的body元素 .append("svg") //添加一个svg元素 .attr("width", width) //设定宽度 .attr("height", height); //设定高度

有了画布,接下来就可以在画布上作图了                    。

绘制矩形

本文绘制一个横向的柱形图        。只绘制矩形                 ,不绘制文字和坐标轴           。

在 SVG 中                     ,矩形的元素标签是 rect                   。例如:

<svg> <rect></rect> <rect></rect> </svg>

上面的 rect 里没有矩形的属性            。矩形的属性    ,常用的有四个:

x:矩形左上角的 x 坐标 y:矩形左上角的 y 坐标 width:矩形的宽度 height:矩形的高度

要注意              ,在 SVG 中                    ,x 轴的正方向是水平向右        ,y 轴的正方向是垂直向下的        。

现在给出一组数据           ,要对此进行可视化                   。数据如下:

var dataset = [ 250 , 210 , 170 , 130 , 90 ]; //数据(表示矩形的宽度)

为简单起见                   ,我们直接用数值的大小来表示矩形的像素宽度(后面会说到这不是一种好方法)               。然后            ,添加以下代码    。

var rectHeight = 25; //每个矩形所占的像素高度(包括空白) svg.selectAll("rect") .data(dataset) .enter() .append("rect") .attr("x",20) .attr("y",function(d,i){ return i * rectHeight; }) .attr("width",function(d){ return d; }) .attr("height",rectHeight-2) .attr("fill","steelblue");

这段代码添加了与 dataset 数组的长度相同数量的矩形        ,所使用的语句是:

svg.selectAll("rect") //选择svg内所有的矩形 .data(dataset) //绑定数组 .enter() //指定选择集的enter部分 .append("rect") //添加足够数量的矩形元素

这段代码以后会常常出现在 D3 的代码中                   ,请务必牢记                    。目前不深入讨论它的作用机制是怎样的               ,只需要读者牢记    ,当:有数据                    ,而没有足够图形元素的时候                  ,使用此方法可以添加足够的元素                  。

添加了元素之后,就需要分别给各元素的属性赋值。在这里用到了 function(d, i)                 ,前面已经讲过                     ,d 代表与当前元素绑定的数据    ,i 代表索引号                 。给属性赋值的时候              ,是需要用到被绑定的数据                    ,以及索引号的                     。

最后一行的:

.attr("fill","steelblue");

是给矩形元素设置颜色    。一般来说        ,最好写成外置 CSS 的形式           ,方便归类和修改              。这里为了便于初学者理解                   ,将样式直接写到元素里                    。

结果图如下所示:

4    、比例尺的使用

比例尺是 D3 中很重要的一个概念            ,上一章里曾经提到过直接用数值的大小来代表像素不是一种好方法        ,本章正是要解决此问题        。

为什么需要比例尺

上一章制作了一个柱形图                   ,当时有一个数组:

var dataset = [ 250 , 210 , 170 , 130 , 90 ];

绘图时               ,直接使用 250 给矩形的宽度赋值    ,即矩形的宽度就是 250 个像素           。

此方式非常具有局限性                    ,如果数值过大或过小                  ,例如:

var dataset_1 = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ]; var dataset_2 = [ 2500, 2100, 1700, 1300, 900 ];

对以上两个数组,绝不可能用 2.5 个像素来代表矩形的宽度                 ,那样根本看不见;也不可能用 2500 个像素来代表矩形的宽度                     ,因为画布没有那么长                   。

于是    ,我们需要一种计算关系              ,能够:

将某一区域的值映射到另一区域                    ,其大小关系不变            。

这就是比例尺(Scale)        。

有哪些比例尺

比例尺        ,很像数学中的函数                   。例如           ,对于一个一元二次函数                   ,有 x 和 y 两个未知数            ,当 x 的值确定时        ,y 的值也就确定了               。

在数学中                   ,x 的范围被称为定义域               ,y 的范围被称为值域    。

D3 中的比例尺    ,也有定义域和值域                    ,分别被称为 domain 和 range                    。开发者需要指定 domain 和 range 的范围                  ,如此即可得到一个计算关系                  。

D3 提供了多种比例尺,下面介绍最常用的两种。

线性比例尺

线性比例尺                 ,能将一个连续的区间                     ,映射到另一区间                 。要解决柱形图宽度的问题    ,就需要线性比例尺                     。

假设有以下数组:

var dataset = [1.2, 2.3, 0.9, 1.5, 3.3];

现有要求如下:

将 dataset 中最小的值              ,映射成 0;将最大的值                    ,映射成 300    。

代码如下:

var min = d3.min(dataset); //得到最小值 var max = d3.max(dataset); //得到最大值 var scaleLinear = d3.scaleLinear() .domain([min, max]) .range([0, 300]); scaleLinear(0.9); //返回 0 scaleLinear(2.3); //返回 175 scaleLinear(3.3); //返回 300

其中        ,d3.scaleLinear() 返回一个线性比例尺              。domain() 和 range() 分别设定比例尺的定义域和值域                    。在这里还用到了两个函数           ,它们经常与比例尺一起出现:

d3.max() d3.min()

这两个函数能够求数组的最大值和最小值                   ,是 D3 提供的        。按照以上代码            ,

比例尺的定义域 domain 为:[0.9, 3.3]

比例尺的值域 range 为:[0, 300]

因此        ,当输入 0.9 时                   ,返回 0;当输入 3.3 时               ,返回 300           。当输入 2.3 时呢?返回 175    ,这是按照线性函数的规则计算的                   。

有一点请大家记住:

d3.scaleLinear() 的返回值                    ,是可以当做函数来使用的            。因此                  ,才有这样的用法:scaleLinear(0.9)        。

序数比例尺

有时候,定义域和值域不一定是连续的                   。例如                 ,有两个数组:

var index = [0, 1, 2, 3, 4]; var color = ["red", "blue", "green", "yellow", "black"];

我们希望 0 对应颜色 red                     ,1 对应 blue    ,依次类推               。

但是              ,这些值都是离散的                    ,线性比例尺不适合        ,需要用到序数比例尺    。

var scaleOrdinal = d3.scaleOrdinal() .domain(index) .range(color); scaleOrdinal (0); //返回 red scaleOrdinal (2); //返回 green scaleOrdinal (4); //返回 black

用法与线性比例尺是类似的                    。

给柱形图添加比例尺

在上一章的基础上           ,修改一下数组                   ,再定义一个线性比例尺                  。

var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ]; var scaleLinear = d3.scaleLinear() .domain([0, d3.max(dataset)]) .range([0, 250]);

其后            ,按照上一章的方法添加矩形        ,在给矩形设置宽度的时候                   ,应用比例尺。

var rectHeight = 25; //每个矩形所占的像素高度(包括空白) svg.selectAll("rect") .data(dataset) .enter() .append("rect") .attr("x",20) .attr("y",function(d,i){ return i * rectHeight; }) .attr("width",function(d){ return scaleLinear(d); //在这里用比例尺 }) .attr("height",rectHeight-2) .attr("fill","steelblue");

如此一来               ,所有的数值    ,都按照同一个线性比例尺的关系来计算宽度                    ,因此数值之间的大小关系不变                 。

5                    、坐标轴

坐标轴                  ,是可视化图表中经常出现的一种图形,由一些列线段和刻度组成                     。坐标轴在 SVG 中是没有现成的图形元素的                 ,需要用其他的元素组合构成    。D3 提供了坐标轴的组件                     ,如此在 SVG 画布中绘制坐标轴变得像添加一个普通元素一样简单              。

坐标轴由什么构成

在 SVG 画布的预定义元素里    ,有六种基本图形:

矩形 圆形 椭圆 线段 折线 多边形

另外              ,还有一种比较特殊                    ,也是功能最强的元素:

路径

画布中的所有图形        ,都是由以上七种元素组成                    。

显然           ,这里面没有坐标轴 这种元素        。如果有的话                   ,我们可以采用类似以下的方式定义:

<axis x1="" x2="" ...></axis>

很可惜            ,没有这种元素           。但是        ,这种设计是合理的:不可能为每一种图形都配备一个单独的元素                   ,那样 SVG 就会过于庞大                   。

因此               ,我们需要用其他元素来组合成坐标轴    ,最终使其变为类似以下的形式:

<g> <!-- 第一个刻度 --> <g> <line></line> <!-- 第一个刻度的直线 --> <text></text> <!-- 第一个刻度的文字 --> </g> <!-- 第二个刻度 --> <g> <line></line> <!-- 第二个刻度的直线 --> <text></text> <!-- 第二个刻度的文字 --> </g> ... <!-- 坐标轴的轴线 --> <path></path> </g>

<g>分组元素                    ,是 SVG 画布中的元素                  ,意思是 group            。此元素是将其他元素进行组合的容器,在这里是用于将坐标轴的其他元素分组存放        。

如果需要手动添加这些元素就太麻烦了                 ,为此                     ,D3 提供了轴生成器:d3.axisTop()                  、d3.axisRight()、

d3.axisBottom()                 、d3.axisLeft()                   。它为我们完成了以上工作               。 定义坐标轴

上一章提到了比例尺的概念    ,要生成坐标轴              ,需要用到比例尺                    ,它们二者经常是一起使用的    。下面        ,在上一章的数据和比例尺的基础上           ,添加一个坐标轴的组件                    。

坐标轴是有朝向的                   ,在这里我们以向下朝向                     、水平方向的坐标轴为例            ,其他朝向的(比如向左朝向的    、垂直的坐标轴)类似                  。

var dataset = [2.5, 2.1, 1.7, 1.3, 0.9]; //数据 //定义线性比例尺 var xScale = d3 .scaleLinear() .domain([0, d3.max(dataset)]) .range([0, 250]); //定义坐标轴 var axis = d3 .axisBottom(xScale) //定义一个axis并指定刻度的方向为bottom(朝下)且指定比例尺为xScale .ticks(7); //指定刻度的数量 在 SVG 中添加坐标轴

定义了坐标轴之后        ,只需要在 SVG 中添加一个分组元素                   ,再将坐标轴的其他元素添加到这里即可。代码如下:

svg.append("g").call(axis);

上面有一个 call() 函数               ,其参数是前面定义的坐标轴 axis                 。

在 D3 中    ,call() 的参数是一个函数                     。调用之后                    ,将当前的选择集作为参数传递给此函数    。也就是说                  ,以下两段代码是相等的              。

function foo(selection) { selection .attr("name1", "value1") .attr("name2", "value2"); } foo(d3.selectAll("div"))

d3.selectAll("div").call(foo);

因此,

svg.append("g").call(axis);

axis(svg.append(g));

意思一致                    。

设定坐标轴的样式和位置

默认的坐标轴样式不太美观                 ,下面提供一个常见的样式:

<style> .axis path, .axis line{ fill: none; stroke: black; shape-rendering: crispEdges; } .axis text { font-family: sans-serif; font-size: 11px; } </style>

分别定义了类 axis 下的 path              、line                    、text 元素的样式        。接下来                     ,只需要将坐标轴的类设定为 axis 即可           。

坐标轴的位置    ,可以通过 transform 属性来设定                   。

通常在添加元素的时候就一并设定              ,写成如下形式:

svg.append("g") .attr("class","axis") .attr("transform","translate(20,130)") .call(axis);

6        、完整的柱形图

一个完整的柱形图包含三部分:矩形           、文字                   、坐标轴            。本章将对前几章的内容进行综合的运用                    ,制作一个实用的柱形图        ,内容包括:选择集            、数据绑定        、比例尺                   、坐标轴等内容        。

添加 SVG 画布 //画布大小 var width = 400; var height = 400; //在 body 里添加一个 SVG 画布 var svg = d3.select("body") .append("svg") .attr("width", width) .attr("height", height); //画布周边的空白 var padding = {left:30, right:30, top:20, bottom:20};

上面定义了一个 padding           ,是为了给 SVG 的周边留一个空白                   ,最好不要将图形绘制到边界上                   。

定义数据和比例尺 //定义一个数组 var dataset = [10, 20, 30, 40, 33, 24, 12, 5]; //x轴的比例尺(创建一个序列化比例尺) var xScale = d3.scaleBand() .domain(d3.range(dataset.length)) .rangeRound([0, width - padding.left - padding.right]); //y轴的比例尺 var yScale = d3.scaleLinear() .domain([0,d3.max(dataset)]) .range([height - padding.top - padding.bottom, 0]);

这里出现了d3.scaleBand()            ,这是一个坐标轴

d3.range(dataset.length)        ,前面说过                   ,这里返回的是一个等差数列               ,dataset.length=9    ,所以返回的是0到8的等差数列

x 轴使用序数化比例尺                    ,y 轴使用线性比例尺               。要注意两个比例尺值域的范围    。

定义坐标轴 var xAxis = d3.axisBottom(xScale); //定义x轴 var yAxis = d3.axisLeft(yScale); //定义y轴

x 轴刻度的方向向下                  ,y 轴的向左                    。

添加矩形和文字元素 //矩形之间的空白 var rectPadding = 4; //添加矩形元素 var rects = svg.selectAll(".MyRect") .data(dataset) .enter() .append("rect") .attr("class", "MyRect") .attr( "transform", "translate(" + padding.left + "," + padding.top + ")" ) .attr("x", function(d, i) { return xScale(i) + rectPadding / 2; }) .attr("y", function(d) { return yScale(d); }) .attr("width", xScale.step() - rectPadding) .attr("height", function(d) { return height - padding.top - padding.bottom - yScale(d); }) .attr("fill","blue"); //添加文字元素 var texts = svg.selectAll(".MyText") .data(dataset) .enter() .append("text") .attr("class", "MyText") .attr( "transform", "translate(" + padding.left + "," + padding.top + ")" ) .attr("x", function(d, i) { return xScale(i) + rectPadding / 2; }) .attr("y", function(d) { return yScale(d); }) .attr("dx", function() { return (xScale.step() - rectPadding) / 2; }) .attr("dy", function(d) { return 20; }) .text(function(d) { return d; });

矩形元素和文字元素的 x 和 y 坐标要特别注意,要结合比例尺给予适当的值                  。

添加坐标轴的元素 //添加x轴 svg.append("g") .attr("class","axis") .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")") .call(xAxis); //添加y轴 svg.append("g") .attr("class","axis") .attr("transform","translate(" + padding.left + "," + padding.top + ")") .call(yAxis);

坐标轴的位置要结合空白 padding 的值来设定。

7               、让图表动起来

D3 支持制作动态的图表                 。有时候                 ,图表的变化需要缓慢的发生                     ,以便于让用户看清楚变化的过程    ,也能给用户不小的友好感                     。

什么是动态效果

前面几章制作的图表是一蹴而就地出现              ,然后绘制完成后不再发生变化的                    ,这是静态的图表    。

动态的图表        ,是指图表在某一时间段会发生某种变化           ,可能是形状    、颜色                    、位置等                   ,而且用户是可以看到变化的过程的              。

例如            ,有一个圆        ,圆心为 (100, 100)                    。现在我们希望圆的 x 坐标从 100 移到 300                   ,并且移动过程在 2 秒的时间内发生        。

这种时候就需要用到动态效果               ,在 D3 里我们称之为过渡(transition)           。

实现动态的方法

D3 提供了 4 个方法用于实现图形的过渡:从状态 A 变为状态 B                   。

transition()

启动过渡效果            。

其前后是图形变化前后的状态(形状                  、位置、颜色等等)    ,例如:

.attr("fill","red") //初始颜色为红色 .transition() //启动过渡 .attr("fill","steelblue") //终止颜色为铁蓝色

D3 会自动对两种颜色(红色和铁蓝色)之间的颜色值(RGB值)进行插值计算                    ,得到过渡用的颜色值        。我们无需知道中间是怎么计算的                  ,只需要享受结果即可                   。

duration()

指定过渡的持续时间,单位为毫秒               。

如 duration(2000)                  ,指持续 2000 毫秒                     ,即 2 秒    。

ease()

指定过渡的方式    ,常用的有:

linear:普通的线性变化 circle:慢慢地到达变换的最终状态 elastic:带有弹跳的到达最终状态 bounce:在最终状态处弹跳几次

调用时              ,格式形如: ease(“bounce                       ”)                    。

delay()

指定延迟的时间                    ,表示一定时间后才开始转变        ,单位同样为毫秒                  。此函数可以对整体指定延迟           ,也可以对个别指定延迟。

例如                   ,对整体指定时:

.transition() .duration(1000) .delay(500)

如此            ,图形整体在延迟 500 毫秒后发生变化        ,变化的时长为 1000 毫秒                 。因此                   ,过渡的总时长为1500毫秒                     。

又如               ,对一个一个的图形(图形上绑定了数据)进行指定时:

.transition() .duration(1000) .delay(funtion(d,i){ return 200*i; })

如此    ,假设有 10 个元素                    ,那么第 1 个元素延迟 0 毫秒(因为 i = 0)                  ,第 2 个元素延迟 200 毫秒,第 3 个延迟 400 毫秒                 ,依次类推….整个过渡的长度为 200 * 9 + 1000 = 2800 毫秒    。

实现简单的动态效果

下面将在 SVG 画布里添加三个圆                     ,圆出现之后    ,立即启动过渡效果              。

第一个圆              ,要求移动 x 坐标                    。

var circle1 = svg.append("circle") .attr("cx", 100) .attr("cy", 100) .attr("r", 45) .style("fill", "green"); //在1秒(1000毫秒)内将圆心坐标由100变为300 circle1.transition() .duration(1000) .attr("cx", 300);

第二个圆                    ,要求既移动 x 坐标        ,又改变颜色        。

var circle2 = svg.append("circle") .attr("cx", 100) .attr("cy", 200) .attr("r", 45) .style("fill", "green"); //与第一个圆一样 //在1.5秒(1500毫秒)内将圆心坐标由100变为300           , //将颜色从绿色变为红色 circle2.transition() .duration(1500) .attr("cx", 300) .style("fill", "red");

第三个圆                   ,要求既移动 x 坐标            ,又改变颜色        ,还改变半径           。

var circle3 = svg.append("circle") .attr("cx", 100) .attr("cy", 300) .attr("r", 45) .style("fill", "green"); //与第一个圆一样 //在2秒(2000毫秒)内将圆心坐标由100变为300 //将颜色从绿色变为红色 //将半径从45变成25 //过渡方式采用bounce(在终点处弹跳几次) circle3 .transition() .duration(2000) .ease(d3.easeBounce) .attr("cx", 300) .style("fill", "red") .attr("r", 25); 给柱形图加上动态效果

在上一章完整柱形图的基础上稍作修改                   ,即可做成一个带动态效果的                 、有意思的柱形图                   。

在添加文字元素和矩形元素的时候               ,启动过渡效果    ,让各柱形和文字缓慢升至目标高度                    ,并且在目标处跳动几次            。

对于文字元素                  ,代码如下:

.attr("y",function(d){ var min = yScale.domain()[0]; return yScale(min); }) .transition() .delay(function(d,i){ return i * 200; }) .duration(2000) .ease(d3.easeBounce) .attr("y",function(d){ return yScale(d); });

文字元素的过渡前后,发生变化的是 y 坐标        。其起始状态是在 y 轴等于 0 的位置(但要注意                 ,不能在起始状态直接返回 0                     ,要应用比例尺计算画布中的位置)                   。终止状态是目标值               。

8                     、理解 Update    、Enter              、Exit

Update                    、Enter        、Exit 是 D3 中三个非常重要的概念    ,它处理的是当选择集和数据的数量关系不确定的情况    。

什么是 Update           、Enter                   、Exit

前几章里              ,反复出现了形如以下的代码                    。

svg.selectAll("rect") //选择svg内所有的矩形 .data(dataset) //绑定数组 .enter() //指定选择集的enter部分 .append("rect") //添加足够数量的矩形元素

前面提到                    ,这段代码使用的情况是当以下情况出现的时候:

有数据        ,而没有足够图形元素的时候           ,使用此方法可以添加足够的元素                  。

当时并没有深究这段代码是什么意思                   ,本章将对此进行讲解。但是            ,由于此问题相对复杂        ,本章只进行最初步的介绍                 。

假设                   ,在 body 中有三个 p 元素               ,有一数组 [3, 6, 9]    ,则可以将数组中的每一项分别与一个 p 元素绑定在一起                     。但是                    ,有一个问题:**当数组的长度与元素数量不一致(数组长度 > 元素数量 or 数组长度 < 元素数量)时呢?**这时候就需要理解 Update            、Enter        、Exit 的概念    。

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jbFyQNr1-1629179770606)(/download/attachments/41324300/1581165812504.png?version=1&modificationDate=1581176415000&api=v2)]

看到这                    ,我想大家能体会到为什么本节最开始处的代码能够给 SVG 内添加足够数量的元素了吧            。它的意思其实是:

此时 SVG 里没有 rect 元素        ,即元素数量为 0        。有一数组 dataset           ,将数组元素数量为 0 的选择集绑定后                   ,选择其 Enter 部分(请仔细看上图)            ,然后添加(append)元素        ,也就是添加足够的元素                   ,使得每一个数据都有元素与之对应                   。

Update 和 Enter 的使用

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

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

var dataset = [ 3 , 6 , 9 , 12 , 15 ]; //选择body中的p元素 var p = d3.select("body").selectAll("p"); //获取update部分 var update = p.data(dataset); //获取enter部分 var enter = update.enter(); //update部分的处理:更新属性值 update.text(function(d){ return "update " + d; }); //enter部分的处理:添加元素后赋予属性值 enter.append("p") .text(function(d){ return "enter " + d; });

结果如下图                  ,update 部分和 enter 部分被绑定的数据很清晰地表示了出来:

update 3 update 6 update 9 enter 12 enter 15

请大家记住:

update 部分的处理办法一般是:更新属性值 enter 部分的处理办法一般是:添加元素后,赋予属性值 Update 和 Exit 的使用

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

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

var dataset = [ 3 ]; //选择body中的p元素 var p = d3.select("body").selectAll("p"); //获取update部分 var update = p.data(dataset); //获取exit部分 var exit = update.exit(); //update部分的处理:更新属性值 update.text(function(d){ return "update " + d; }); //exit部分的处理:修改p元素的属性 exit.text(function(d){ return "exit"; }); //exit部分的处理通常是删除元素 // exit.remove();

结果如下              ,请大家区分好 update 部分和 exit 部分。这里为了表明哪一部分是 exit                    ,并没有删除掉多余的元素        ,但实际上 exit 部分的绝大部分操作是删除                 。

update 3 exit exit

请大家记住:

exit 部分的处理办法一般是:删除元素(remove)

9                   、交互式操作

与图表的交互           ,指在图形元素上设置一个或多个监听器                   ,当事件发生时            ,做出相应的反应                     。

什么是交互

交互        ,指的是用户输入了某种指令                   ,程序接受到指令之后必须做出某种响应    。对可视化图表来说               ,交互能使图表更加生动    ,能表现更多内容              。例如                    ,拖动图表中某些图形               、鼠标滑到图形上出现提示框    、用触屏放大或缩小图形等等                    。

用户用于交互的工具一般有三种:鼠标                    、键盘                  、触屏        。

如何添加交互

对某一元素添加交互操作十分简单                  ,代码如下:

var circle = svg.append("circle"); circle.on("click", function(){ //在这里添加交互内容 });

这段代码在 SVG 中添加了一个圆,然后添加了一个监听器                 ,是通过 on() 添加的           。在 D3 中                     ,每一个选择集都有 on() 函数    ,用于添加事件监听器                   。

on() 的第一个参数是监听的事件              ,第二个参数是监听到事件后响应的内容                    ,第二个参数是一个函数            。

鼠标常用的事件有:

click:鼠标单击某元素时        ,相当于 mousedown 和 mouseup 组合在一起        。 mouseover:光标放在某元素上                   。 mouseout:光标从某元素上移出来时               。 mousemove:鼠标被移动的时候    。 mousedown:鼠标按钮被按下                    。 mouseup:鼠标按钮被松开                  。 dblclick:鼠标双击。

键盘常用的事件有三个:

keydown:当用户按下任意键时触发           ,按住不放会重复触发此事件                 。该事件不会区分字母的大小写                   ,例如“A         ”和“a      ”被视为一致                     。 keypress:当用户按下字符键(大小写字母、数字                 、加号                     、等号    、回车等)时触发            ,按住不放会重复触发此事件    。该事件区分字母的大小写              。 keyup:当用户释放键时触发        ,不区分字母的大小写                    。 触屏常用的事件有三个: touchstart:当触摸点被放在触摸屏上时        。 touchmove:当触摸点在触摸屏上移动时           。 touchend:当触摸点从触摸屏上拿开时                   。 当某个事件被监听到时                   ,D3 会把当前的事件存到 d3.event 对象               ,里面保存了当前事件的各种参数    ,请大家好好参详            。如果需要监听到事件后立刻输出该事件                    ,可以添加一行代码: circle.on("click", function(){ console.log(d3.event); }); 带有交互的柱形图

将前面柱状图的部分代码修改成如下代码        。

var rects = svg.selectAll(".MyRect") .data(dataset) .enter() .append("rect") .attr("class","MyRect") //把类里的 fill 属性清空 .attr("transform","translate(" + padding.left + "," + padding.top + ")") .attr("x", function(d,i){ return xScale(i) + rectPadding/2; } ) .attr("y",function(d){ return yScale(d); }) .attr("width", xScale.step() - rectPadding ) .attr("height", function(d){ return height - padding.top - padding.bottom - yScale(d); }) .attr("fill","steelblue") //填充颜色不要写在CSS里 .on("mouseover",function(d,i){ d3.select(this) .attr("fill","yellow"); }) .on("mouseout",function(d,i){ d3.select(this) .transition() .duration(500) .attr("fill","steelblue"); });

这段代码添加了鼠标移入(mouseover)                  ,鼠标移出(mouseout)两个事件的监听器                   。监听器函数中都使用了 d3.select(this),表示选择当前的元素                 ,this 是当前的元素                     ,要改变响应事件的元素时这么写就好               。

mouseover 监听器函数的内容为:将当前元素变为黄色

mouseout 监听器函数的内容为:缓慢地将元素变为原来的颜色(蓝色)

10              、布局

布局    ,可以理解成 “制作常见图形的函数                       ”              ,有了它制作各种相对复杂的图表就方便多了    。

布局是什么

布局                    ,英文是 Layout                    。从字面看        ,可以想到有“决定什么元素绘制在哪里             ”的意思                  。布局是 D3 中一个十分重要的概念。D3 与其它很多可视化工具不同           ,相对来说较底层                   ,对初学者来说不太方便            ,但是一旦掌握了        ,就比其他工具更加得心应手                 。下图展示了 D3 与其它可视化工具的区别:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4zHdMtx9-1629179770609)(/download/attachments/41324300/1581167394482.png?version=1&modificationDate=1581176415000&api=v2)]

可以看到                   ,D3 的步骤相对来说较多                     。坏处是对初学者不方便                    、也不好理解    。好处是能够制作出更加精密的图形              。因此               ,我们可以据此定义什么时候选择 D3 比较好:

选择 D3:如果希望开发脑海中任意想象到的图表                    。 选择 Highcharts        、Echarts 等:如果希望开发几种固定种类的           、十分大众化的图表        。

看起来    ,D3 似乎是为艺术家或发烧友准备的           。有那么点意思                    ,但请初学者也不要放弃                   。

如何理解布局

从上面的图可以看到                  ,布局的作用是:将不适合用于绘图的数据转换成了适合用于绘图的数据            。

因此,为了便于初学者理解                 ,布局的作用解释成:数据转换        。

布局有哪些

D3 总共提供了 12 个布局:饼状图(Pie)                   、力导向图(Force)            、弦图(Chord)        、树状图(Tree)                   、集群图(Cluster)               、捆图(Bundle)    、打包图(Pack)                    、直方图(Histogram)                  、分区图(Partition)、堆栈图(Stack)                 、矩阵树图(Treemap)                     、层级图(Hierarchy)                   。

12 个布局中                     ,层级图(Hierarchy)不能直接使用               。集群图    、打包图              、分区图                    、树状图        、矩阵树图是由层级图扩展来的    。如此一来    ,能够使用的布局是 11 个(有 5 个是由层级图扩展而来)                    。这些布局的作用都是将某种数据转换成另一种数据              ,而转换后的数据是利于可视化的                  。

Bundle —- 捆图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-giecBFN8-1629179770610)(/download/attachments/41324300/1581167469030.png?version=1&modificationDate=1581176415000&api=v2)]

Chord —- 弦图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d9Wiuw9u-1629179770612)(/download/attachments/41324300/1581167483157.png?version=1&modificationDate=1581176415000&api=v2)]

Cluster —- 集群图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nMtPMpIm-1629179770613)(/download/attachments/41324300/1581167499717.png?version=1&modificationDate=1581176415000&api=v2)]

Force —- 力学图           、力导向图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2UNpgRaY-1629179770614)(/download/attachments/41324300/1581167512490.png?version=1&modificationDate=1581176415000&api=v2)]

Histogram —- 直方图(数据分布图)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3NWkfusx-1629179770615)(/download/attachments/41324300/1581167526523.png?version=1&modificationDate=1581176415000&api=v2)]

Pack —- 打包图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-37UZ6ncS-1629179770616)(/download/attachments/41324300/1581167538005.png?version=1&modificationDate=1581176415000&api=v2)]

Partition —- 分区图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P5knvexg-1629179770617)(/download/attachments/41324300/1581167549590.png?version=1&modificationDate=1581176415000&api=v2)]

Pie —- 饼状图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hMZvE37L-1629179770617)(/download/attachments/41324300/1581167561567.png?version=1&modificationDate=1581176415000&api=v2)]

Stack —- 堆栈图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r7DO8BjF-1629179770619)(/download/attachments/41324300/1581167572871.png?version=1&modificationDate=1581176415000&api=v2)]

Tree —- 树状图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pG9OUCWC-1629179770620)(/download/attachments/41324300/1581167585333.png?version=1&modificationDate=1581176415000&api=v2)]

Treemap —- 矩阵树图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rsFGuklC-1629179770621)(/download/attachments/41324300/1581167595875.png?version=1&modificationDate=1581176415000&api=v2)]

11                   、饼状图

本章制作一个饼状图。在布局的应用中                    ,最简单的就是饼状图        ,通过本文你将对布局有一个初步了解                 。

1            、数据准备

var marge = {top:60,bottom:60,left:60,right:60} var svg = d3.select("svg") var width = svg.attr("width") var height = svg.attr("height") var g = svg.append("g") .attr("transform","translate("+marge.top+","+marge.left+")"); var dataset = [ 30 , 10 , 43 , 55 , 13 ];//需要将这些数据变成饼状图的数据

2        、设置一个颜色比例尺

//设置一个color的颜色比例尺           ,为了让不同的扇形呈现不同的颜色 var colorScale = d3.scaleOrdinal() .domain(d3.range(dataset.length)) .range(d3.schemeCategory10);

3                   、新建一个饼状图

//新建一个饼状图 var pie = d3.pie();

4               、新建一个弧形生成器

//新建一个弧形生成器 var innerRadius = 0;//内半径 var outerRadius = 100;//外半径 var arc_generator = d3.arc() .innerRadius(0) .outerRadius(100);

5    、利用饼状图生成器转换数据

//将原始数据变成可以绘制饼状图的数据                   , var pieData = pie(dataset); //在浏览器的控制台打印pieData console.log(pieData);

6                    、开始绘制            ,老规矩        ,先为每一个扇形及其对应的文字建立一个分组

var gs = g.selectAll(".g") .data(pieData) .enter() .append("g") .attr("transform","translate("+width/2+","+height/2+")")//位置信息

7                  、绘制扇形

//绘制饼状图的各个扇形 gs.append("path") .attr("d",function(d){ return arc_generator(d);//往弧形生成器中出入数据 }) .attr("fill",function(d,i){ return colorScale(i);//设置颜色 });

arc_generator(d);//往弧形生成器中出入数据                   ,由官方API的示例可知(我已经在本章开头截了图)               ,弧形生成器所需要传入的数据就是饼状图生成器返回的数据

8、文字

//绘制饼状图上面的文字信息 gs.append("text") .attr("transform",function(d){//位置设在中心处 return "translate("+arc_generator.centroid(d)+")"; }) .attr("text-anchor","middle") .text(function(d){ return d.data; })

注意:这里的文字获取需要 用到d.data    ,我们可以根据在控制台输出的数据格式可以知道                    ,因为在转换数据后                  ,新数据的data域才是原始数据

最后,整个代码的结果:<%

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
如何把硬盘模式改为ahci(怎么将电脑硬盘模式修改为ahci模式) python提取字段(python如何提取文本信息?)