前言
上一篇文章 我们讲了 D3.js
中一些常见的 API
,并且通过一个 demo 了解了 D3.js
是如何工作的。铺垫完之后,这篇文章我们正儿八经的来实现一个柱状图。
正文
比例尺
比例尺是 D3.js
中一个重要的概念,它用于在值和坐标之间的相互转换。本文中出现的相关 API 如下👇
API | 说明 |
---|---|
scaleBand | 一般用于将一组离散值映射到连续范围的值 |
scaleLinear | 线性转换,将连续的输入域映射到连续的输出范围 |
想象一下,我们需要在一个 800 x 600 宽高的容器内绘制一个坐标系。通常情况下,坐标的数值不会与实际的宽高完全对应。因此,我们需要一种工具来将实际的宽高与坐标系中的数值进行映射。
对于 scaleLinear
这个线性转换函数,可以用下面的公式来描述:
$y = mx + b(b 为任意常量)$
通过输入 $x$(通常是一个数值),我们可以获得元素在页面上的高度或宽度。
绘制坐标系
首先我们先添加初始代码:引入 D3.js
& 设置基础样式
<html>
<head>
<title>Bar</title>
<style>
#bar {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="bar"></div>
</body>
<script src="<https://d3js.org/d3.v7.min.js>"></script>
</html>
紧接着我们来创建一个 svg,宽高为:800 x 600
const width = 800;
const height = 600;
const data = Array.from({length: 26}).map((_, i) => ({
name: String.fromCharCode(65 + i),
value: Math.random() * 100
}))
const svg = d3.select('#bar')
.append('svg')
.attr('width', width)
.attr('height', height)
此时页面上依旧是光秃秃的一片,没关系,我们先把 x 轴加上:
const xScale = d3.scaleBand().domain(data.map(item => item.name)).range([0, 500]).padding(0.1)
const xAxis = d3.axisBottom(xScale)
svg.append('g').call(xAxis)
此时,页面已经出现了我们需要的 x 轴
随后我们把 y 轴也加到页面上:
const yScale = d3.scaleLinear().domain([0, 100]).range([500, 0])
const yAxis = d3.axisLeft(yScale)
svg.append('g').call(yAxis)
此时页面就会出现一个奇怪的坐标系😱😱😱
当然如果你看完了上一篇文章,你就知道这是因为坐标原点在左上角导致的🤔
因此我们在绘制 x 轴的时候还需要把它的位置调整一下
svg.append('g').attr('transform', `translate(0, 500)`).call(xAxis
那么写到这里,我们就得到了一个长得挺好看的坐标系
添加柱状图
添加坐标系之后,我们就可以开始添加柱状图了。
在此之前有一些细节需要说明:我们可以利用 xScale
或 yScale
来根据网页上实际需要展示的值,来决定柱状图的展示位置。比如,下面这段代码:
const xScale = d3.scaleBand().domain(data.map(item => item.name)).range([0, 500]).padding(0.1)
执行之后,我们可以通过 name → value
的映射,来获取 x 轴上每一个离散点的具体位置,同理 y 轴也是如此。
根据这点,我们就不需要再花太多时间计算每个矩形的的 x、y 坐标了,而是能直接通过 xScale
、yScale
这些函数来进行简单的换算来达到我们想要的效果。代码如下:
svg.selectAll('rect')
.data(data)
.join('rect')
.attr('x', item => xScale(item.name))
.attr('y', item => yScale(item.value))
.attr('width', xScale.bandwidth())
.attr('height', item => 500 - yScale(item.value))
.attr('fill', 'steelblue')
效果如下👇
补充动画
D3.js
中的动画逻辑是这样的:
- 设置初始值,比如 x、y
- 添加动画配置,比如动画函数、持续时间等等
- 设置最终值,比如
width
、height
svg.selectAll('rect')
.data(data)
.join('rect')
// 设置 x 坐标,防止动画时出现抖动
.attr('x', item => xScale(item.name))
.attr('y', 500)
// 设置宽度,柱状图的宽度在这里一直保持不变即可
.attr('width', xScale.bandwidth())
// 为了有动画效果,这里先设置高度为 0
.attr('height', 0)
.transition()
// 设置延迟
.delay((item, i) => i * 20)
// 添加动画函数
.ease(d3.easeCubic)
// 设置动画时长
.duration(1000)
// 最终的效果
.attr('y', item => yScale(item.value))
.attr('height', item => 500 - yScale(item.value))
.attr('fill', 'steelblue')
总结
本文中我们了解了比例尺并且熟悉了 D3.js
中一些与之相关的 API
,并且通过一系列步骤了解了怎么通过 D3.js
来实现一个柱状图。
想要了解更多前端知识,欢迎关注我的公众号:tony老师的前端补习班
系列文章:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。