3278 слов
16 минут
Class1-Introduction
2026-06-13
Нет тегов
Эта статья не переведена на текущий язык. Показывается на основном языке.

数据可视化工具 D3.js 介绍#

D3.js简略介绍#

D3.js 是一个用于在网页上创建交互式数据的可视化 JavaScript 库。它提供了一组用于处理数据、创建图表和动画的函数,使得开发人员可以轻松地创建动态的、交互式的数据可视化。 D3.js 的主要特点包括:

  1. 强大的数据处理能力:D3.js 提供了丰富的数据处理函数,如选择、过滤、聚合等,使得开发人员可以轻松地处理数据。
  2. 可视化效果丰富:D3.js 提供了丰富的可视化图表类型
  3. 动画效果丰富:D3.js 提供了丰富的动画效果,如缓动、缓动函数等,使得开发人员可以轻松地创建动态的动画效果。
  4. 跨平台支持:D3.js 支持多种平台,如浏览器、Node.js 等,使得开发人员可以轻松地使用 D3.js 在各种环境中创建可视化。
  5. 社区活跃:D3.js 有广大社区,提供了丰富的资源,如文档、教程、示例等,使得开发人员可以轻松地找到需要的资源。

D3.js的安装#

D3.js 可以通过 npm 安装,使用命令如下:

npm install d3

如果是使用TypeScript进行开发的话 则需要下载额外的类型声明文件

npm install @types/d3

在此之后 可以在项目中使用D3.js了 在程序import中引入d3.js

import * as d3 from "d3"

之后就可以通过类似d3.select()等方法来操作DOM元素了

D3.js的入门知识#

一般情况下 D3.js 往往配合SVG元素使用,SVG是一种用于描述二维矢量图形的XML标记语言,它被用于创建动态的、交互式的图形。 首先需要创建一个SVG元素,然后使用D3.js提供的函数来操作SVG元素,如选择、过滤、聚合等。

图1:创建一个SVG元素

可交互图表
<svg class="diagram"/>
<script>
d3.select(svg).attr("style","background:gray")
</script>
True Size:0 × 0
ViewBox Size:600 × 400

然后我们通过D3.js来选中这个SVG元素,并使用一些函数来操作它。

D3.js核心函数#

d3.select()
attr("data-name",value)
data(data_list)
append("element")
enter()

d3.select()可以通过id class等选择器选中一个组件 比如

d3.select("svg.diagram") //选中类名为diagram的svg元素

attr可以操作元素的属性 也就是html元素写在开头括号里面的值 例如

<div className={"divClass"}/>

此div中的className就是属性的一种

SVG元素的基本组件以及语法#

Rect组件(矩形)#

<rect
x="x-coordinate" <!-- 矩形左上角的 x 坐标 -->
y="y-coordinate" <!-- 矩形左上角的 y 坐标 -->
width="width-value" <!-- 矩形的宽度 -->
height="height-value" <!-- 矩形的高度 -->
rx="rx-value" <!-- 矩形的圆角半径(水平方向) -->
ry="ry-value" <!-- 矩形的圆角半径(垂直方向) -->
fill="fill-color" <!-- 矩形的填充颜色 -->
stroke="stroke-color" <!-- 矩形的描边颜色 -->
stroke-width="width-value" <!-- 矩形的描边宽度 -->
/>

图2:Rect的使用

可交互图表
rect.attr('x',30).attr('y',30) //设置矩形的起始坐标为(30,30)
.attr('width',300).attr('height',300) //设置矩形的宽高分别为300
.attr('fill','red') //设置矩形填充颜色为红色
.attr('stroke','blue') //设置矩形的描边颜色为蓝色
.attr('stroke-width',5) //设置矩形的描边宽度为5
True Size:0 × 0
ViewBox Size:600 × 400

Circle组件(圆形)#

<circle
cx="x-coordinate" <!-- 圆心的 x 坐标 -->
cy="y-coordinate" <!-- 圆心的 y 坐标 -->
r="radius" <!-- 圆的半径 -->
fill="fill-color" <!-- 圆的填充颜色 -->
stroke="stroke-color" <!-- 圆的描边颜色 -->
stroke-width="width" <!-- 圆的描边宽度 -->
/>

图3:Circle的使用

可交互图表
circle.attr('cx',30).attr('cy',30) //设置圆心为(30,30)
.attr('r',20) //设置半径为20
.attr('fill','red') //设置填充颜色为红色
True Size:0 × 0
ViewBox Size:600 × 400

Line组件(线段)#

<line
x1="x1-coordinate" <!-- 起点的 x 坐标 -->
y1="y1-coordinate" <!-- 起点的 y 坐标 -->
x2="x2-coordinate" <!-- 终点的 x 坐标 -->
y2="y2-coordinate" <!-- 终点的 y 坐标 -->
stroke="stroke-color" <!-- 直线的颜色 -->
stroke-width="width" <!-- 直线的宽度 -->
/>

图4:Line的使用

可交互图表
line.attr('x1',30).attr('y1',30) //设置Line的起始坐标为(30,30)
.attr('x2',300).attr('y2',200) //设置Line的终点坐标为(300,200)
.attr('stroke','red').attr('stroke-width',3) //设置Line颜色为红色 粗细为3
True Size:0 × 0
ViewBox Size:600 × 400

Path组件(路径)#

<path
d="path-data" <!-- 定义路径的路径数据 -->
fill="fill-color" <!-- 路径的填充颜色 -->
stroke="stroke-color" <!-- 路径的描边颜色 -->
stroke-width="width" <!-- 路径的描边宽度 -->
/>

d 属性定义了路径的路径数据,即路径命令序列。 路径数据由一系列的路径命令组成,每个路径命令以字母开头,后面跟随一组数字参数。 常用的路径命令包括:

  • M(移动到)
  • L(直线到)
  • H(水平线到)
  • V(垂直线到)
  • C(三次贝塞尔曲线)
  • S(光滑曲线)
  • Q(二次贝塞尔曲线)
  • T(光滑二次贝塞尔曲线)
  • A(圆弧)
  • Z(闭合路径)等。

图5:Path的使用

可交互图表
path.attr('d','M100 100 L200 200 L300 100 L400 400')
//设置线段移动轨迹 (100,100) -> (200,200) -> (300,100) -> (400,400)
.attr('stroke','blue')
.attr('stroke-width',5)
.attr('fill','none')
True Size:0 × 0
ViewBox Size:600 × 400

Text组件(文本)#

<text
x="x-coordinate" <!-- 文本左上角的 x 坐标 -->
y="y-coordinate" <!-- 文本左上角的 y 坐标 -->
font-family="font" <!-- 字体名称 -->
font-size="size" <!-- 字体大小 -->
fill="fill-color" <!-- 文本颜色 -->
text-anchor="anchor" <!-- 文本锚点 -->
>
Text content <!-- 文本内容 -->
</text>

图6:Text的使用

可交互图表
const text=d3.select(svg).append('text')
text.attr('x',200).attr('y',200) //设置文本的起始坐标为(200,200)
.text('Hello World') //设置文本内容为"Hello World"
.attr('font-family','sans-serif') //设置字体为sans-serif
.attr('fill','black') //设置文本颜色为黑色
.attr('font-size',40) //设置字体大小为40
True Size:0 × 0
ViewBox Size:600 × 400

D3的链式函数调用#

图7:D3的链式调用示例

可交互图表
const svg=d3.select(".diagram")
svg.attr("width",600).attr("height",400)//设置svg的属性为宽600高400
.attr("style","background:red") //设置svg的style 背景颜色为红色
True Size:0 × 0
ViewBox Size:600 × 400

D3.js通过一连串链式调用的函数来操作SVG元素,体现了函数式编程的思想.

而且在attr函数里面 第二个参数可以不是一个值而是一个函数 这个函数接受两个参数 第一个参数是数据本身 第二个参数是当前元素的索引 返回一个值作为attr的值 如

attr("height",(d,i)=>i*100)

比如我们现在有一个数组 我们来用这个data模拟一个最简单的柱状图

const data=[12,10,19,10,4,3,4,5,6,7]

然后让我们把这个数组作为数据绑定到rect元素上

const rects=d3.select(svg).selectAll('rect').data(data).enter().append('rect')

然后我们根据数据来设置rect的宽高 x属性是根据索引来设置的 每一个rect的x坐标都是50的倍数 y坐标为20 因此每一个柱的起始坐标都是(50*i,20) 宽度恒定为40 高度根据数据乘以10来设定

rects.attr('x',(d,i)=>i*50).attr('y',20).attr('width',40).attr('height',(d)=>10*d)

在设定x坐标和高度的时候 我们就希望让每一个rect的x坐标和高度根据数据动态变化 这时候就可以使用attr的第二个参数作为函数的形式来实现 这个函数的第一个参数d就是数据本身 i就是当前元素的索引

图8:数据的绑定与绘制

可交互图表
const data=[12,10,19,10,4,3,4,5,6,7]
const rects=d3.select(svg).selectAll('rect').data(data).enter().append('rect')
rects.attr('x',(d,i)=>i*50).attr('y',20).attr('width',40).attr('height',(d)=>10*d)
True Size:0 × 0
ViewBox Size:600 × 400

数据绑定中 enter update exit 三个部分的区别解释#

在数据绑定中,D3.js会将数据数组中的每个元素与DOM元素进行匹配,这通常被称为数据绑定。在绑定过程中,D3.js会将数据数组中的元素映射到DOM元素上,以便我们可以根据数据的变化动态更新DOM元素

enter update exit的图解(图片来源于 https://www.bookstack.cn/read/d3wiki/enterexit.md )#

图标未加载

enter()#

enter()函数用于处理新数据项,这些数据项在数据绑定之前并不存在于DOM中。当数据数组中的元素数量增加时,D3.js会调用enter()函数来创建新的DOM元素,并将这些元素与新增的数据项进行绑定。

update()#

update()函数用于处理已存在的DOM元素,这些元素在数据绑定之后存在于DOM中。当数据数组中的元素数量减少时,D3.js会调用update()函数来更新现有的DOM元素,使其与新数据项保持一致。

exit()#

exit()函数用于处理不再存在于数据数组中的DOM元素。当数据数组中的元素数量减少时,D3.js会调用exit()函数来删除不再需要的DOM元素。

D3的比例尺函数#

介绍#

比例尺函数是D3.js中用于将数据映射到可视化元素的一种重要工具。 它能够将数据的范围映射到可视化元素的范围,例如将数据的值映射到图形的大小、颜色或位置等。比例尺函数可以分为线性比例尺、对数比例尺、时间比例尺等不同类型,可以根据数据的特点选择合适的比例尺函数。

  • 线性比例尺: 用于将线性数据映射到线性空间,例如将数据的值映射到图形的大小或位置。 例如,将数据的值映射到柱状图的宽度或高度。
const xScale=d3.scaleLinear().domain([0,100]).range([100,900])
//将100~900像素之间映射到0~100的值
  • 对数比例尺: 用于将对数数据映射到线性空间,例如将数据的值映射到图形的大小或位置。 例如,将数据的值映射到散点图的大小。
const yScale=d3.scaleLog().domain([1,1000]).range([100,900])
  • 还有其他的各种各样的比例尺 在需要用到的时候再进行介绍

Range与Domain#

  • Range:表示映射后的范围,即在视觉上要映射到的目标范围。例如,将数据映射到像素坐标,则Range就是像素坐标的范围。
  • Domain:表示映射前的范围,即原始数据的取值范围。 例如,我们可以通过设置Domain和Range来确定比例尺的映射方式。例如,我们可以将Domain设置为[0,1],Range设置为[0,100],这样,将数据映射到100个像素的宽度上,其中0映射到0像素,1映射到100像素。
const xScale=d3.scaleLinear().domain([0,1]).range([0,100])
xScale(0.5) //返回50
xScale(1) //返回100

学完比例尺之后 我们再回到刚刚讲到的柱状图例子中

rects.attr('x',(d,i)=>i*50).attr('y',20).attr('width',40).attr('height',(d)=>10*d)

在这里我们是通过索引设置x的值和height的值的 但是我们会发现每次都要这样运算会十分麻烦 因此我们可以使用比例尺来简化这个图像

图9:使用比例尺绘图

可交互图表
const xScale=d3.scaleLinear().domain([0,data.length-1]).range([50,500])
const yScale=d3.scaleLinear().domain([0,Math.max(...data)]).range([0,300])
rects.attr('x',(d,i)=>xScale(i)) //通过X比例尺计算X坐标
.attr('y',20)
.attr('width',40)
.attr('height',(d)=>yScale(d)) //通过Y比例尺计算Y坐标
True Size:0 × 0
ViewBox Size:600 × 400

但是在这里我们又发现了一个问题 按正常阅读习惯来说的话 柱状图应该是从下往上长的 但是因为(0,0)点在左上角(如图)

无标题

可交互图表
True Size:0 × 0
ViewBox Size:600 × 400

现在是反过来的 为了实现这个效果 我们需要将比例尺的范围反过来 利用比例尺实现这个功能也十分简单 我们只需要让range的顺序反过来即可

图11:比例尺反向映射

可交互图表
const yScale=d3.scaleLinear().domain([0,Math.max(...data)]).range([300,0])
//调转range的参数顺序 使其反向映射
True Size:0 × 0
ViewBox Size:600 × 400

这样的话 0对应的是300 max值对应0 恰好就可以将图像反过来了

坐标轴#

  1. 创建比例尺
d3.axisBottom(scale)//通过比例尺创建一个刻度位于底部的水平坐标轴
d3.axisTop(scale)//通过比例尺创建一个刻度位于顶部的水平坐标轴
d3.axisLeft(scale)// 通过比例尺创建一个刻度位于左侧的垂直坐标轴
d3.axisRight(scale)// 通过比例尺创建一个刻度位于右侧的垂直坐标轴
  1. 将比例尺添加到svg上 创建比例尺之后 我们再根据比例尺 创建X Y坐标轴并绘制在svg上面 这里我们使用d3的call函数

图12:绘制坐标轴

可交互图表
const xAxis = d3.axisBottom(xScale)
const yAxis = d3.axisLeft(yScale)
d3.select(svg).append('g').attr('transform','translate(0,350)').call(xAxis)
d3.select(svg).append('g').attr('transform','translate(100,50)').call(yAxis)
True Size:0 × 0
ViewBox Size:600 × 400

‘g’元素是一个svg里面的容器元素,也就是group,用于将某一系列的元素进行分组,用于组合其他元素,如线、文本等。 因为坐标轴是由多个元素组合而成的 我们可以使用g元素把组成坐标轴的所有元素放进一个分组里面 d3的坐标轴非常智能 它可以根据具体比例和数据大小 自动推断刻度的距离

实战:使用D3绘制一个简单的折线图#

const data=[12,10,19,10,4,3,4,5,6,7]

1.创建一个svg元素#

图13:新建一个SVG元素

可交互图表
const svg = d3.select("#chart").append("svg").attr("width",600).attr("height",600)
True Size:0 × 0
ViewBox Size:600 × 400

2.创建比例尺#

经过分析发现 我们的数据量为10 通过合理的分析我们决定设置svg宽度为600 高度为400 然后让我们创建x y比例尺

const xScale=d3.scaleLinear().domain([0,data.length-1]).range([50,550])
const yScale=d3.scaleLinear().domain([0,Math.max(...data)]).range([350,50])

这里为了使图像更加美观 我们让x的range为50~550之间 也就是左右留出50px的边距 y轴同理

3.创建坐标轴#

图14:绘制坐标轴

可交互图表
const xScale=d3.scaleLinear().domain([0,data.length-1]).range([50,550])
const yScale=d3.scaleLinear().domain([0,Math.max(...data)]).range([350,50])
const xAxis=d3.axisBottom(xScale).ticks(10)
const yAxis=d3.axisLeft(yScale).ticks(5)
d3.select(svg).append('g').attr('transform','translate(0,350)').call(xAxis)
//设置x轴的transform坐标偏移 使其位于(0,350)
d3.select(svg).append('g').attr('transform','translate(50,0)').call(yAxis)
//设置y轴的transform坐标偏移 使其位于(50,0)
True Size:0 × 0
ViewBox Size:600 × 400

4.绘制线段#

坐标轴绘制完成后 我们再通过path元素来绘制一条线

图15:绘制折线

可交互图表
svg.append("path")
.attr("d",d3.line()(data.map((d,i)=>[xScale(i),yScale(d)])))
//d就是这一条折线经过的所有点的x y坐标
.attr("fill","none")
//设置线的fill为none 就是不填充线下面的空间
.attr("stroke","red").attr("stroke-width",3)
//设置线的颜色为红色 宽度为3
True Size:0 × 0
ViewBox Size:600 × 400

5.绘制数据点#

线绘制完成后 我们接下来绘制所有的点

图16:绘制数据点

可交互图表
svg.selectAll("points").data(data).enter().append("circle").attr("class","point")
.attr("cx",(_,i)=>xScale(i)).attr("cy",(d)=>yScale(d))
//设置点的x y坐标
.attr("r",4).attr("fill","red")
//设置点的半径为4 颜色为红色
True Size:0 × 0
ViewBox Size:600 × 400

6.绘制数据文字#

最后 我们在点的上方绘制数据对应的值

图17:绘制数据文字

可交互图表
svg.selectAll("data-text").data(data).enter().append("text").attr("class","data-text")
.attr("text-anchor","middle")
//设置文字居中显示
.attr("x",(_,i)=>xScale(i)).attr("y",(d)=>yScale(d)-10)
//设置各个数据文字的坐标 注意yScale(d)-10的作用是让数据文字出现在点的上方
.text((d)=>d)
True Size:0 × 0
ViewBox Size:600 × 400
Class1-Introduction
https://blog.aquamarinez.com/ru/docs/d3tutorial/class1-introduction/
Автор
Aquamarine
Опубликовано в
2026-06-13
Лицензия
CC BY-NC-SA 4.0