Js+SVG 柱狀圖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
svg,
.container {
box-sizing: border-box;
padding: 8px;
border-radius: 3px;
border: 1px solid #ddd;
}
svg {
background-color: #f1f1f1;
}
.container {
background-color: #fff;
}
</style>
</head>
<body>
<div class="container"></div>
<script>
onload = function () {
let width = '100%',
height = 256,
barHeight = 16;
let dataset = new Array(15);
for (let i = 0; i < dataset.length; i++) {
(dataset[i] = Number.parseInt(Math.random() * 1000, 10));
}
let body = document.querySelector('.container');
let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('width', width);
svg.setAttribute('height', height);
dataset.forEach((v, idx) => {
let r = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
r.setAttribute('y', barHeight * idx);
r.setAttribute('width', v);
r.setAttribute('height', barHeight - 4);
r.setAttribute('fill', '#369');
r.setAttribute('ry', '2px');
r.setAttribute('fill-opacity', 0.85);
svg.appendChild(r);
let t = document.createElementNS('http://www.w3.org/2000/svg', 'text');
t.setAttribute('x', v + 4);
t.setAttribute('y', (idx + 1) * barHeight - 6);
t.setAttribute('font-size', '0.75em');
t.textContent = v;
svg.appendChild(t);
});
body.appendChild(svg);
};
</script>
</body>
</html>
D3+SVG 柱狀圖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<style>
svg,
.container {
box-sizing: border-box;
padding: 8px;
border-radius: 3px;
border: 1px solid #ddd;
}
svg {
background-color: #f1f1f1;
}
.container {
background-color: #fff;
}
</style>
<div class="container"></div>
<script src="../../source/d3.js"></script>
<script>
let width = '100%',
height = 256,
barHeight = 16;
let dataset = new Array(15);
for (let i = 0; i < dataset.length; i++) {
(dataset[i] = Number.parseInt(Math.random() * 1000, 10));
}
let svg = d3.select('.container').append('svg');
svg.attr('width', width)
.attr('height', height);
let rectes = svg.selectAll('rect')
.data(dataset)
.enter()
.append('rect');
rectes
.attr('y', (item, idx) => idx * barHeight)
.attr('width', item => item)
.attr('height', barHeight - 4)
.attr('ry', '2px')
.attr('fill-opacity', 0.85)
.attr('fill', '#369')
let title = svg.selectAll('text')
.data(dataset)
.enter()
.append('text');
title.attr('x', item => item + 4)
.attr('y', (_, idx) => (idx + 1) * barHeight - 6)
.attr('font-size', '0.75em')
.text(item => item)
</script>
</body>
</html>
Js vs D3
兩個段代碼實現(xiàn)的效果是相同的.
總的來說, 通過比較上述代碼, 可以看的出來:
- 創(chuàng)建 SVG 元素
Js 創(chuàng)建一個 SVG 元素相對復(fù)雜, 需要指定 namespaceURI
, 通常這個值等于 http://www.w3.org/2000/svg(也可以點擊網(wǎng)址查看更多信息), 寫作 document.createElementNS('http://www.w3.org/2000/svg', 'svg');
雖說看起來挺長的, 不過總的來說也并不是那么復(fù)雜就是了. 另外, 關(guān)于 namespaceURI, vscode 的提示信息內(nèi)可以復(fù)制到, 其他編輯器并未測試.
D3 創(chuàng)建一個 SVG 元素就很簡單了, Selection.append('svg');
.
- 編程方式
Js 是普通的逐行編寫.
D3 看起來更加傾向于鏈?zhǔn)?
- 批量生成元素
Js 需要書寫遍歷函數(shù), 在循環(huán)體內(nèi)編寫創(chuàng)建 SVG 元素的代碼.
D3 不需要我們自己來寫遍歷函數(shù), 采用了 .data(dataset).enter().append(元素名)
的方式自動補(bǔ)全元素.
- 補(bǔ)齊元素(本例并不明顯)
這個所謂的補(bǔ)齊元素的概念, 其出發(fā)點可能是為了性能優(yōu)化吧, 具體來講就是:
當(dāng)文檔中已經(jīng)存在了 N 個 rect 元素(就拿 rect 元素舉例), 然后由于某種原因, 原本對應(yīng)這 N 個 rect 元素的數(shù)組發(fā)生了改變, 變成了 M 個.
此時如果不考慮那么多, 直接移除所有的 rect 在重新遍歷一遍顯然也不是不行! 不過總感覺如此大量的刪/插元素并不是什么好的選擇.
可能是因此, D3 才提出了補(bǔ)齊/刪齊元素的說法, 以求盡量少的刪/插元素吧.
總之此時:
Js 可能需要計算了, 比如現(xiàn)有 N 個元素, M 個數(shù)據(jù); 需要劃分 3 中情況來分別進(jìn)行編寫.
D3 提供了一段通用的代碼
// Update 情形2
var p = d3.select("body")
.selectAll("p")
.data([4, 8, 15, 16, 23, 42])
.text(function(d) { return d; });
// Enter 情形1
p.enter().append("p")
.text(function(d) { return d; });
// Exit 情形3
p.exit().remove();
結(jié)語
就制作一個簡單的條形圖而言, 還沒有特別強(qiáng)烈的感到使用 D3 能夠帶來莫大的好處.