前言
上一篇文章 我們講了 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老師的前端補習班
系列文章: