本篇大綱:選擇最合適的圖表、圓餅圖、本次範例的畫面與互動效果、pie( ) 與 arc( )、繪製圓餅圖
終於要正式進到一天一張圖的篇章了!在開始繪製圖表之前,很重要的一點是:如何為資料選擇最合適的圖表呈現。
圖表分成很多種,有圓餅圖、長條圖、折線圖、散點圖等等,為什麼不乾脆用一種圖表呈現資料就好嗎?這是因為每一種圖表適合呈現的資料不一樣。當我們拿到一組資料後,就要依照我們的目的,找到最適合的圖表來將這組資料呈現給別人看。
下面這張圖將各種圖表適合用來表達的事情整理出來
( 圖片來源 )
我這邊用文字簡單整理常用的幾種圖表,以及它們適合呈現的資料
適合用在 | 比較資料 | 整體占比 | 了解分布 | 分析趨勢 |
---|---|---|---|---|
圖表 | 長條圖、折線圖 | 圓餅圖、長條堆積圖、面積圖 | 散點圖、氣泡圖 | 折線圖 |
想更瞭解該怎麼選擇圖表的人,可以另外看看這幾篇不錯的文章
瞭解完該選擇哪種圖表之後,開始來畫第一張圖吧!圓餅圖適合用來表達 每筆資料於整體的占比
,生活中最常見的地方就是記帳App啦~常用App來記帳的人一定都看過這種圖
透過這種圓餅圖或甜甜圈圖,我們就能弄清楚自己的錢都花到哪裡、哪邊的支出佔最多,今天就來練習畫一張圓餅帳本圖吧!
這次我們要做的範例畫面與互動效果有:
實際範例如下
繪製圓餅圖之前,我們要先知道 d3.arc( )
與 d3.pie( )
這兩個方法跟它們細節設定。關於 d3.arc( ) 的用法在 Day9 講過了,今天再來講講 d3.pie 的用法吧!
d3.arc( ) 跟 a3.pie( ) 通常都是都配一起使用。當我們用arc( )建立好圓弧之後,就能將資料帶進 pie( )的方法中去建立圓餅圖。pie( ) 包含以下幾種API:
很多設定跟 arc( ) 的設定類似,像是兩者都有 startAngle、endAngle、padding等API,它們的功能也是一樣的,我們就直接進入下方的範例做一次吧!
繪製圓餅圖之前,我們先把要進行的步驟稍微拆解一下:
接著就按照這些順序來撰寫程式碼吧!首先,先建立資料
// css
.chartContainer {
margin: auto;
width: 80%;
min-width: 200px;
/* height: 600px; */
margin: auto;
}
//html
<h4 class="text-center mt-5">金金的帳本</h4>
<div class="chartContainer"></div>
<div>
<button type="button" class="btn btn-primary January">1月</button>
<button type="button" class="btn btn-primary Feburary">2月</button>
</div>
// JS
// Data
let data = [{item:'交通', data:30},{item:'房租', data:45},
{item:'其他', data:9},{item:'吃飯', data:67},{item:'娛樂', data:22}];
// 切換一二月資料
d3.select('.Feburary').on('click', function(){
data = [{item:'交通', data:50},{item:'房租', data:65},
{item:'其他', data:39},{item:'吃飯', data:17},{item:'娛樂', data:72}];
drawPie()
})
d3.select('.January').on('click', function(){
data = [{item:'交通', data:30},{item:'房租', data:45},
{item:'其他', data:9},{item:'吃飯', data:67},{item:'娛樂', data:22}];
drawPie()
})
const drawPie = () => {
// RWD 清除原本的圖型
d3.select('svg').remove()
// svg圖形區大小、邊界
const svgWidth = parseInt(d3.select(".chartContainer").style("width")),
svgHeight = svgWidth*0.8,
margin = 40;
// 先設定 svg 大小
const svg = d3.select(".chartContainer")
.append("svg")
.attr("width", svgWidth)
.attr("height", svgHeight);
// 圖表與線條、標籤
svg.append("g")
.attr("class", "slices")
.attr('transform', `translate(${svgWidth / 2}, ${svgHeight / 2})`);
svg.append("g")
.attr("class", "labels");
svg.append("g")
.attr("class", "lines");
// 接下來的程式碼都放這邊哦.....
// 接下來的程式碼都放這邊哦.....
// 接下來的程式碼都放這邊哦.....
}
drawPie()
// 設定顏色
const color = d3.scaleOrdinal()
.range(["#4BEFCF","#0bbc17","#F96262", '#ffbe32', '#e271fc']);
// radius 用來設定半徑,圓餅圖的圓弧大小是區域的一半
const radius = Math.min(svgWidth, svgHeight) / 2 - margin;
// 設定每個資料在圓餅圖上:
const piechart = d3.pie()
.value(d => d.data)
.sort(function(a,b){
console.log(a,b) // 固定圓餅圖的項目排序
return d3.ascending(a.key, b.key)
});
// innerRadius 跟 outerRadius 決定圓餅內圈外圈的大小 radius
const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius)
.padAngle(.02),
outerArc = d3.arc()
.outerRadius(radius * 0.9)
.innerRadius(radius * 0.9),
data_ready = piechart(data)
// 計算每塊資料的占比%
// 先用 d3.sum 加總全部資料,再將資料一一除上總數
const total = d3.sum(data, d => d.data)
data.forEach(d => {
d.percentage = Math.round((d.data/total)*100)
})
// 建立pie
const cutePie = svg.select('.slices')
.selectAll('g')
.data(data_ready)
.enter()
.append('g')
.attr('class', 'arc')
cutePie.append('path')
.attr('d', arc)
.attr('fill', color)
.attr("stroke", "#fff")
.style("stroke-width", "2px")
.style("opacity", 1);
// 加上每個區塊的標示
// 控制文字的位置
const arcText = d3.arc()
.innerRadius(radius)
.outerRadius(radius - 10)
const itemText = cutePie.append('text')
.attr('transform', d => `translate(${arcText.centroid(d)})`)
.text(d => d.data.item + d.data.percentage + '%')
.style('text-anchor', 'middle')
.style('font-size', 16)
.style('fill', 'black')
// 滑鼠互動 mouseover、mouseleave
d3.selectAll('.arc path')
.style('cursor', 'pointer')
.on('mouseover', function(){
d3.select(this)
.transition()
.duration(500)
.style("filter", "drop-shadow(2px 4px 6px black)")
.style('transform', 'scale(1.1)')
})
.on('mouseleave', function(){
d3.select(this)
.transition()
.duration(500)
.style("filter", "drop-shadow(0 0 0 black)")
.style('transform', 'scale(1)')
})
這樣就完成啦!最後的最後,別忘了要用 window resize 把完成的圓餅圖調整為 RWD 圓餅圖唷
// RWD
d3.select(window).on("resize", drawPie);
想看完整的程式碼請往這走 Github ,想看完成的實際畫面請往這走 Github Page,需要的人請自行取用~