一個可以簡單用 JS 操作 SVG 的框架。
推薦資料來源:
使用
主要會使用到包含:
Copy <line> elements for the edges
<text> elements for the labels
<circle> elements to represent the nodes
<g> elements as containers that move the nodes and labels together
1.選擇元素
Copy d3.select('')
d3.selectAll('')
2.設定屬性
Copy d3.select('').attr('width', 20)
設定 style
Copy .style("fill", "#69b3a2")
3.新增元素
Copy d3.select('').append("svg")
4.設定相關範圍,讓數值縮小
Copy const x = d3.scaleLinear()
.domain([0, 4000]) // 數值範圍
.range([ 0, width ]); // 實際顯示範圍
5.傳入資料並且遍歷
記得 append 前要用 selectAll 相同東西,不然不會顯示
Copy const data = [{...}...]
d3.select('#test')
.selectAll('circle')
.data(data)
.enter() // 類似forEach
.append("circle")
6.添加座標軸
Copy const data = [{
case: 23,
}....]
let aScale = d3
.scaleLinear()
.domain([0, d3.max(data, (d) => d.cases)])
.range([0, 300]);
d3.select("#scatterplot #x-axis")
.call(d3.axisBottom(aScale).ticks(5));
7. 加上動畫
Copy .transition()
.duration(1000)
地圖
typojson 比 geojson 檔案小。
以下範例讀取 typojson 然後用 相關套件轉換為geojson 並顯示到 d3 上
https://github.com/topojson/topojson-client/blob/master/README.md#feature
Copy d3.json('data/world.json').then(world => {
let projection = d3.geoWinkel3().scale(140).translate([365, 225]);
let geoPath = d3.geoPath(projection);
const svg = d3
.select("#map-chart")
.append("svg")
.attr("width", 365 * 2)
.attr("height", 225 * 2);
svg
.selectAll("path")
.data(topojson.feature(world, world.objects.countries).features)
.enter()
.append("path")
.attr("d", geoPath)
.attr("class", "country");
});
加上地圖線
Copy var graticule = d3.geoGraticule();
svg
.append("path")
.datum(graticule)
.attr("class", "graticule line")
.attr("d", geoPath);
svg
.append("path")
.datum(graticule.outline)
.attr("class", "graticule outline")
.attr("d", geoPath);
css
Copy .graticule {
fill: none;
stroke: #777;
stroke-width: .5px;
stroke-opacity: .2;
pointer-events: none;
}
.graticule.outline {
stroke-width: 2px;
}
更新 x 與 y 軸
merge 與 exit().remove() 是給傳入 .data 用的,如果是軸要用以下方式判斷
Copy if(!document.querySelector('.wrapper-group g')) {
// 第一次 init
d3.select(".wrapper-group")
.attr("transform", "translate(180, 10)")
.append("g")
.attr("id", "x-axis")
.attr("transform", `translate(0,${this.height})`)
.call(d3.axisBottom(xScale).ticks(5));
d3.select(".wrapper-group")
.append("g")
.attr("id", "y-axis")
.attr("transform", "translate(0,0)")
.call(d3.axisLeft(yScale).ticks(5));
} else {
// 更新 axis
d3.select(".wrapper-group #x-axis")
.call(d3.axisBottom(xScale).ticks(5));
d3.select(".wrapper-group #y-axis")
.call(d3.axisLeft(yScale).ticks(5));
}
畫 x, y 軸標籤
必須要手動添加 text,如果沒有顯示試著加在 svg 標籤下
Copy // 畫 y 軸 標籤
d3.select(".plot-svg")
.append("g")
.attr(
"transform",
"translate(" + this.width / 6 + ", " + this.height / 2 + ")"
)
.append("text")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.text('test');
事件綁定
點擊後觸發顏色改變
Copy ......
.on('click', function(e) {
d3.select(this).style("fill", 'black');
})
讓顏色變深
Copy .on('click', function(e) {
d3.select(this).style("fill", d3.color(d3.select(this).attr("fill")).darker());
})
隱藏動畫
如果要讓隱藏和顯示有動畫,必須用 opacity,display: none
會沒作用
Copy d3.select(ele)
.select("text")
.transition()
.duration(600)
.attr("opacity", switchOn ? 1 : 0);
Forcing
類似於物體碰撞等物理效果
https://github.com/d3/d3-force
v3 之後的用法有改變
範例:
https://codepen.io/EasonWang01/pen/RwRoXZb https://bl.ocks.org/HarryStevens/f636199a46fc4b210fbca3b1dc4ef372