利用D3.js实现数据可视化的简单示例
目录
一、D3.js选择器
二、数据绑定相关方法
三、DOM操作方法
四、事件监听
五、实现折线图案例
1.首先引入 D3.js 库。
2.然后获取数据(这里定义了销售数据数组作为数据)。
3.接着创建一个 svg 元素作为画布
4.定义 x 轴和 y 轴的比例尺,x 轴使用 scaleBand 比例尺来处理离散的月份数据,y 轴使用 scaleLinear 比例尺根据销售金额的范围来确定坐标范围
5.分别添加 x 轴和 y 轴到 svg 画布上。
6.定义折线生成器
7.使用数据绘制折线和数据点
8.监听事件并添加处理函数
使用D3.js过程中,我们一般需要创建画布、绑定数据、选择元素、操作元素、监听元素事件等,因此,需要先了解D3.js的选择器、数据绑定方式、DOM操作方法、事件监听等。
一、D3.js选择器
1. d3.select() :.
- 选择第一个匹配的 DOM 元素。
- 用法:`d3.select(selector)`,其中 `selector` 是 CSS 选择器字符串。
2. d3.selectAll() :
- 选择所有匹配的 DOM 元素。
- 用法:`d3.selectAll(selector)`,其中 `selector` 是 CSS 选择器字符串。
二、数据绑定相关方法
1.enter() :
- 为数据绑定过程中未匹配的元素创建新的 DOM 元素。
- 用法:`selection.enter()`。
2.exit() :
- 为数据绑定过程中多余的元素(即数据减少时)提供操作。
- 用法:`selection.exit()`。
3.data() :
- 将数据绑定到 DOM 元素上。
- 用法:`selection.data(data)`,其中 `data` 是要绑定的数据。
三、DOM操作方法
1.attr() :
- 获取或设置 DOM 元素的属性。
- 用法:`selection.attr(name, value)`。
2.style() :
- 获取或设置 DOM 元素的样式。
- 用法:`selection.style(name, value)`。
3.text() :
- 获取或设置 DOM 元素的文本内容。
- 用法:`selection.text(value)`。
4.html() :
- 获取或设置 DOM 元素的 HTML 内容。
- 用法:`selection.html(value)`。
5.append() :
- 在选定的元素中添加新的子元素。
- 用法:`selection.append(name)`,其中 `name` 是新元素的标签名。
6.remove() :
- 移除选定的元素。
- 用法:`selection.remove()`。
四、事件监听
1.on() :
- 为 DOM 元素添加事件监听器。
- 用法:`selection.on(eventName, listener)`。
五、实现折线图案例
DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>D3.js实现折线图案例title>
<style>
svg {
width: 600px;
height: 400px;
border: 1px solid #ccc;
}
style>
head>
<body>
<script src="https://d3js.org/d3.v7.min.js">script> <script>
// 销售数据
const salesData = [ { month: 'Jan', amount: 12000 }, { month: 'Feb', amount: 15000 }, { month: 'Mar', amount: 18000 }, { month: 'Apr', amount: 16000 }, { month: 'May', amount: 20000 }, { month: 'Jun', amount: 22000 } ];
// 定义 svg 画布
const svg = d3.select('body').append('svg');
// 定义 x 轴比例尺
const xScale = d3.scaleBand()
.domain(salesData.map(d => d.month))
.range([0, 500])
.padding(0.2);
// 定义 y 轴比例尺
const yScale = d3.scaleLinear()
.domain([0, d3.max(salesData, d => d.amount)])
.range([300, 0]);
// 添加 x 轴
svg.append('g')
.attr('transform', 'translate(50,300)')
.call(d3.axisBottom(xScale));
// 添加 y 轴
svg.append('g')
.attr('transform', 'translate(50,0)')
.call(d3.axisLeft(yScale));
// 添加折线
const line = d3.line()
.x(d => xScale(d.month) + 25)
.y(d => yScale(d.amount));
svg.append('path')
.datum(salesData)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 2)
.attr('d', line);
// 添加数据点
svg.selectAll('.dot')
.data(salesData)
.enter()
.append('circle')
.attr('class', 'dot')
.attr('cx', d => xScale(d.month) + 25)
.attr('cy', d => yScale(d.amount))
.attr('r', 5) .attr('fill', 'blue');
// 添加提示框(简单示例,未完整实现交互)
svg.selectAll('.dot')
.on('mouseover', function (event, d) {
d3.select(this).attr('r', 8);
// 这里可以进一步完善提示框内容和样式的显示
console.log(`Month: ${d.month}, Amount: ${d.amount}`);
})
.on('mouseout', function (event, d) {
d3.select(this).attr('r', 5);
});
script>
body>
html>
1.首先引入 D3.js 库。
<script src="https://d3js.org/d3.v7.min.js">script> <script>
2.然后获取数据(这里定义了销售数据数组作为数据)。
3.接着创建一个 svg
元素作为画布
const svg = d3.select('body').append('svg');
4.定义 x
轴和 y
轴的比例尺,x
轴使用 scaleBand
比例尺来处理离散的月份数据,y
轴使用 scaleLinear
比例尺根据销售金额的范围来确定坐标范围
// 定义 x 轴比例尺
const xScale = d3.scaleBand()
.domain(salesData.map(d => d.month))
.range([0, 500])
.padding(0.2);
d3.scaleBand()
:创建一个分带(离散)比例尺,适用于处理分类数据。domain(salesData.map(d => d.month))
:设置比例尺的输入域(Domain)。这里从salesData
数组中提取每个数据对象的month
属性,形成一个包含所有月份的数组作为输入域。range([0, 500])
:设置比例尺的输出范围(Range),将输入域映射到从 0 到 500 的区间。padding(0.2)
:设置每个类别之间的间隔为带宽的 20%,避免数据标签相互重叠。
// 定义 y 轴比例尺
const yScale = d3.scaleLinear()
.domain([0, d3.max(salesData, d => d.amount)])
.range([300, 0]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(salesData, d => d.amount)])
.range([300, 0]);
d3.scaleLinear()
:创建一个线性比例尺,用于处理连续数据。domain([0, d3.max(salesData, d => d.amount)])
:设置输入域。这里输入域的下限是 0,上限是salesData
数组中amount
属性的最大值,通过d3.max
函数计算得出。range([300, 0])
:设置输出范围。在 SVG 坐标系中,y 轴是从上到下递增的,所以这里将较大的数据值映射到较小的 y 坐标,范围是从 300(底部)到 0(顶部)。
5.分别添加 x
轴和 y
轴到 svg
画布上。
// 添加 x 轴
svg.append('g')
.attr('transform', 'translate(50,300)')
.call(d3.axisBottom(xScale));
// 添加 y 轴
svg.append('g')
.attr('transform', 'translate(50,0)')
.call(d3.axisLeft(yScale));
svg.append('g')
:在 SVG 元素中添加一个<g>
(分组)元素,用于容纳坐标轴的所有组件。attr('transform', 'translate(50,300)')
:对<g>
元素应用平移变换,将其移动到坐标 (50, 300) 的位置。这是为了将 x 轴放置在合适的位置上。call(d3.axisBottom(xScale))
:调用d3.axisBottom
函数创建一个底部坐标轴,并将xScale
比例尺应用到该坐标轴上,然后将坐标轴添加到<g>
元素中。call(d3.axisLeft(yScale))
调用d3.axisLeft
函数创建一个左侧坐标轴,并将yScale
比例尺应用到该坐标轴上,然后将坐标轴添加到<g>
元素中。
6.定义折线生成器
// 添加折线
const line = d3.line()
.x(d => xScale(d.month) + 25)
.y(d => yScale(d.amount));
svg.append('path')
.datum(salesData)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 2)
.attr('d', line);
d3.line()
:创建一个折线生成器。x(d => xScale(d.month) + 25)
:定义折线在 x 方向上的坐标获取方式。对于每个数据点,通过xScale
比例尺将月份数据映射到 x 坐标,并加上 25 是为了使折线稍微偏离坐标轴一点,让数据点在坐标轴刻度的中间位置。y(d => yScale(d.amount))
:定义折线在 y 方向上的坐标获取方式。通过yScale
比例尺将销售金额数据映射到 y 坐标。svg.append('path')
:在 SVG 元素中添加一个<path>
元素,用于绘制折线。datum(salesData)
:将salesData
数组绑定到<path>
元素上。attr('fill', 'none')
:设置填充颜色为无。attr('stroke', 'steelblue')
:设置描边颜色为钢蓝色。attr('stroke-width', 2)
:设置描边宽度为 2。attr('d', line)
:将折线生成器生成的路径描述设置给<path>
元素的d
属性,从而绘制出折线。
7.使用数据绘制折线和数据点
// 添加数据点
svg.selectAll('.dot')
.data(salesData)
.enter()
.append('circle')
.attr('class', 'dot')
.attr('cx', d => xScale(d.month) + 25)
.attr('cy', d => yScale(d.amount))
.attr('r', 5)
.attr('fill', 'blue');
svg.selectAll('.dot')
:选择所有类名为.dot
的元素。由于此时可能还没有这些元素,这一步主要是为后续的数据绑定和元素创建做准备。data(salesData)
:将salesData
数据绑定到选择的元素上。如果选择的元素数量少于数据点数量,enter()
方法将用于创建新的元素。enter()
:返回一个占位符选择集,用于创建新的元素来匹配多余的数据点。append('circle')
:为每个多余的数据点创建一个<circle>
元素。attr('class', 'dot')
:为创建的<circle>
元素设置类名为.dot
。attr('cx', d => xScale(d.month) + 25)
:设置圆形的cx
(圆心的 x 坐标)。通过xScale
比例尺将数据中的月份转换为 x 坐标,并加上 25 使圆形位于坐标轴刻度中间。attr('cy', d => yScale(d.amount))
:设置圆形的cy
(圆心的 y 坐标)。通过yScale
比例尺将数据中的销售金额转换为 y 坐标。attr('r', 5)
:设置圆形的半径为 5。attr('fill', 'blue')
:设置圆形的填充颜色为蓝色。
8.监听事件并添加处理函数
// 添加提示框(简单示例,未完整实现交互)
svg.selectAll('.dot')
.on('mouseover', function (event, d) {
d3.select(this).attr('r', 8);
// 这里可以进一步完善提示框内容和样式的显示
console.log(`Month: ${d.month}, Amount: ${d.amount}`);
})
.on('mouseout', function (event, d) {
d3.select(this).attr('r', 5);
});