如何學習D3.js
用D3.js製作長條圖學習重要步驟
-
-
D3.js
-
112
- 發佈於 2025-01-17
- 更新於 2025-01-17
9
<button type="button" onclick="click_me()" class="btn btn-sm col-4 col-sm-2 mb-2" style="background-color:#084298;color:white;">點我!</button>
<div id="myplot"></div>
d3_article1.js
<h1> </h1><div class="raw-html-embed"><div class="row d-flex justify-content-center align-items-center mt-3 mb-4">
<div class="col-10 catalog">
<div class="text-center" style="color:#f1f3f4;background:#393939;">目錄</div>
<div id="catalog_content">
<a href="#heading1">D3.js是什麼?</a><br>
<a href="#heading2">D3.js的核心</a><br>
<a href="#heading3">開始學習D3.js之前:先備知識</a><br>
<a href="#heading4">學習起手式:D3.js的重要功能</a><br>
<a href="#heading41" class="ms-3">1.選擇</a><br>
<a href="#heading42" class="ms-3">2.選擇集</a><br>
<a href="#heading43" class="ms-3">3.比例尺</a><br>
<a href="#heading44" class="ms-3">4.座標軸</a><br>
<a href="#heading45" class="ms-3">5.資料綁定</a><br>
<a href="#heading46" class="ms-3">6.繪製圖形</a><br>
<a href="#heading47" class="ms-3">7.事件互動</a><br>
<a href="#heading48" class="ms-3">8.過渡動畫</a><br>
<a href="#heading5">參考資料</a>
</div>
</div>
</div></div><p> </p><div class="raw-html-embed"><h3 id="heading1"> D3.js是什麼?</h3></div><p><span style="background-color:transparent;color:#000000;">D3.js(Data-Driven Documents)主要是用來操作Document Object Model(DOM)樹的JavaScript函式庫,常用於在瀏覽器中建立動態且可互動的圖形、圖表和儀表板等資料視覺化應用。</span></p><p><span style="background-color:transparent;color:#000000;">由於D3常被用於資料視覺化,因此容易被誤會為:</span></p><ol><li><span style="background-color:transparent;color:#000000;">是一個圖形函式庫</span></li><li><span style="background-color:transparent;color:#000000;">以xy座標顯示目前位置</span></li><li><span style="background-color:transparent;color:#000000;">建構在圓形或矩形等圖形上</span></li><li><span style="background-color:transparent;color:#000000;">直接將圖形畫在畫布上</span></li></ol><p><span style="background-color:transparent;color:#000000;">然而,D3實際上是:</span></p><ol><li><span style="background-color:transparent;color:#000000;">是一個操作DOM樹的函式庫</span></li><li><span style="background-color:transparent;color:#000000;">選擇DOM樹中節點為目前位置</span></li><li><span style="background-color:transparent;color:#000000;">建構在節點和DOM元素上</span></li><li><span style="background-color:transparent;color:#000000;">透過屬性建立元素樣式</span></li></ol><p><span style="background-color:transparent;color:#000000;">簡單來說,D3的典型操作是「透過選擇DOM樹的節點位置,綁定資料後增加元素並調整其屬性,以建立圖形」。</span></p><p> </p><div class="raw-html-embed"><h3 id="heading2"> D3.js的核心</h3>
</div><p><span style="background-color:transparent;color:#000000;">D3的典型操作是「透過<strong>選擇</strong>DOM樹的節點位置,綁定<strong>資料</strong>後增加<strong>元素</strong>並調整其<strong>屬性</strong>,以建立圖形」。由此可見,圖形與圖表的起源是「資料綁定(Data-Join)」,它是D3的核心,也是D3被稱為資料驅動(Data-Driven)的原因。當我們要為圖表切換資料集時,若原先存在的元素數量不等於新資料集的資料數量,資料綁定可以完美解決這個問題,因為它能「根據資料增加元素」與「資料更新時修改元素」,自動地以資料為準建構元素,提供很大的便利。</span></p><div class="raw-html-embed"><h3 id="heading3">開始學習D3.js之前:先備知識</h3>
</div><p><span style="background-color:transparent;color:#000000;">由於D3是一種網頁技術,因此在學習D3前,建議具備以下知識:</span></p><ul><li><span style="background-color:transparent;color:#000000;">瀏覽器與伺服器</span></li><li><span style="background-color:transparent;color:#000000;">HTML與CSS</span></li><li><span style="background-color:transparent;color:#000000;">JS</span></li><li><span style="background-color:transparent;color:#000000;">DOM API與事件模型</span></li><li><span style="background-color:transparent;color:#000000;">SVG與Canvas</span></li></ul><div class="raw-html-embed"><h3 id="heading4">學習起手式:D3.js的重要步驟</h3>
</div><p><span style="background-color:transparent;color:#000000;">D3在資料視覺化的用途十分廣泛,由於建構在元素上,經過各種組合可以製作出許多種圖表。舉凡常見的長條圖、折線圖、散佈圖、圓餅圖與直方圖,較冷門的力導向圖、弦圖、樹狀圖與矩陣樹狀圖,或是地圖都可以透過D3實現。</span></p><p><span style="background-color:transparent;color:#000000;">雖然能利用D3製作許多圖表,但不同圖表的操作原理與基礎步驟是相似的,如同前述的典型操作般,只要大致掌握使用步驟與重要功能,就能更快速學習以陡峭學習曲線聞名的D3。因此,以下提供了一些我認為新手學習D3不容錯過的重要步驟,分別是「選擇」、「選擇集」、「比例尺」、「座標軸」、「資料綁定」、「繪製圖形」、「事件互動」與「過渡動畫」,並以長條圖作為範例。</span></p><p><span style="background-color:transparent;color:#000000;">未來網站上會有更詳細的D3教學文章,有興趣的人可以先儲存文章或訂閱網站。</span></p><p><span style="background-color:transparent;color:#000000;">我們先建立兩個資料集,作為長條圖的資料點。</span></p><pre><code class="language-python">//長條圖的Y軸資料,按一下長條圖會切換資料集
let data1=[2,6,7,4,5,6,3,1,7,10];
let data2=[1,4,9,8,5,6,7,3,2,4];
</code></pre><div class="raw-html-embed"><h4 id="heading41">1.選擇</h4>
</div><p><span style="background-color:transparent;color:#000000;">可透過CSS選擇器或DOM API選擇一個或多個元素(html標籤),選定的目標作為後續處理的標的,是必須的步驟。</span></p><p> </p><div class="raw-html-embed"><h4 id="heading42">2.選擇集</h4>
</div><p><span style="background-color:transparent;color:#000000;">前項步驟回傳的物件為選擇集(selection),用來增加、插入和刪除元素以及修改元素屬性。</span></p><pre><code class="language-python">//先在指定位置增加svg元素,再增加g元素,方便一次移動全部元素
let svg=d3.select("#myplot") //1.選擇:選定id為myplot的區塊
.append("svg") //2.選擇集:增加svg元素
.attr("width", svgWidth+margin.left+margin.right)
.attr("height", svgHeight+margin.top+margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);//以左上角為原點,往右移動30,往下移動30
</code></pre><div class="raw-html-embed"><h4 id="heading43">3.比例尺</h4>
</div><p><span style="background-color:transparent;color:#000000;">映射某個區間的數值到另一個區間。簡單來說,就是將圖表資料裝進螢幕空間中,因為螢幕空間有限,在顯示長條圖柱狀長度時,不可能以1000像素呈現同等的數值1000,所以透過比例尺,將全部圖表資料換算成可放進固定螢幕空間的數值。比例尺分為包含連續值的線性、指數對數、量子和分位、設定值比例尺,與不包含連續值的序數比例尺。</span></p><pre><code class="language-python">//3.比例尺:x座標軸比例尺
let xScale=d3.scaleBand()
.range([0,svgWidth]) //圖表實際寬度
.domain([...data1.keys()]) //x軸資料:[0,1,2,...,9]
//3.比例尺:y座標軸比例尺
//由於原點座標為左上角,非左下角,因此將range與domain範圍設定為相反,後續可直接輸入y軸資料
let yScale=d3.scaleLinear()
.range([svgHeight,0]) //圖表實際高度
.domain([0, d3.max(data1)]) //資料範圍:由0到最大值
.clamp(true) //若輸入超過domain範圍,輸出不會超出range範圍
</code></pre><div class="raw-html-embed"><h4 id="heading44">4.座標軸</h4>
</div><p><span style="background-color:transparent;color:#000000;">常見的x/y軸,需搭配比例尺使用。可透過調整軸位置、刻度樣式(方向/間隔/長度/文字樣式)產出美觀的座標軸。</span></p><pre><code class="language-python">//4.座標軸:x座標軸
let xAxis=d3.axisBottom(xScale) //刻度數值朝下
.tickSize(3); //刻度長度
//4.座標軸:y座標軸
let yAxis=d3.axisLeft(yScale)
.ticks(5) //座標軸的分隔數
.tickSize(3); //刻度長度
//將x座標軸含刻度打包在一起
svg.append('g')
.attr('transform', `translate(0,${svgHeight})`)
.call(xAxis);
//將y座標軸含刻度打包在一起
svg.append('g')
.attr('transform', 'translate(5,0)')
.call(yAxis);
</code></pre><div class="raw-html-embed"><h4 id="heading45">5.資料綁定</h4>
</div><p><span style="background-color:transparent;color:#000000;">D3的核心概念。前項步驟結束時,選擇集還沒有資料,因此透過資料綁定,將資料一對一地綁到元素(選擇集)上。當資料數量與元素數量不一致時,運用Update、Enter與Exit,自動使他們達成一致,無須人工手動調整數量。</span></p><div class="raw-html-embed"><h4 id="heading46">6.繪製圖形</h4>
</div><p><span style="background-color:transparent;color:#000000;">增加元素組成圖形。元素包含矩形(長條圖/直方圖)、圓形(散佈圖)、線段(折線圖)、區域(堆疊折線圖)、弧(圓餅圖)、弦(弦圖)或符號(散佈圖中的資料點)。</span></p><pre><code class="language-python">//將每一個資料點的矩形和數值標籤打包在一起,並令其class為bars方便後續動畫鎖定位置
let each=svg.append('g')
.attr('transform', 'translate(5,0)')
.attr('class','bars');
const rectWidth=(svgWidth-margin.left-margin.right)/data1.length; //矩形的寬度
//增加矩形元素
let rect=each.selectAll('rect') //5.資料綁定:綁定資料前,先創造空的元素,建立預留空間方便後續填入內容
.data(data1) //5.資料綁定:一對一結合rect元素和資料集,但實際上還沒有rect元素
.enter()//5.資料綁定:存取所有沒被對應到元素的資料點
.append('rect') //6.繪製圖形:增加矩形元素
.attr('x', (d,i)=>xScale(i)) //i代表每一資料點的索引,以左上角為原點,x座標按索引順序排列 +rectWidth/2
.attr('y',d=>yScale(d)) //由於已調整過比例尺,可直接輸入資料點,此y座標為矩形最上方座標,矩形面積是往下延伸的
.attr('height',d=>svgHeight-yScale(d)) //300為圖表實際高度,上述y座標為資料點實際高度,因此往下延伸矩形面積填滿圖表高度
.attr('width',rectWidth) //矩形寬度
.style('fill','lightblue'); //顏色為淡藍色
//增加文字元素作為數值標籤
let text=each.selectAll('text')
.data(data1)
.enter()
.append('text')
.style('fill', 'lightblue')
.attr('font-size','14px') //文字大小
.attr('font-weight', 600) //文字粗細
.attr('text-anchor','middle') //文字置中
.attr('x', (d,i)=>xScale(i)) //與矩形的座標相同
.attr('y',d=>yScale(d)) //與矩形的座標相同
.attr('dx',rectWidth/2) //微調標籤位置
.attr('dy',-2) //微調標籤位置
.text(d=>d);
</code></pre><div class="raw-html-embed"><h4 id="heading47">7.事件互動</h4>
</div><p><span style="background-color:transparent;color:#000000;">使用者可透過滑鼠、鍵盤與觸控螢幕與圖表互動,例如用滑鼠點擊圖表顯示資料標籤、拖曳圖形或縮放圖表大小等方式。原理是透過在元素上建立監聽器,改變互動標的物的屬性。滑鼠事件包含點擊、移入、移出、移動、按下與鬆開,鍵盤包含接觸、移動與拿開,行動裝置則提供接觸、移動與拿開觸控螢幕的功能。</span></p><div class="raw-html-embed"><h4 id="heading48">8.過渡動畫</h4>
</div><p><span style="background-color:transparent;color:#000000;">在一定時間內流暢地改變元素的屬性,例如顏色、大小、位置等等,適合用來切換資料集。原理是運用內插函數,獲得變化過程中的數值,以改變元素的狀態,內插函數包含線性、逐漸加快速度、彈簧般接近終點等方式。</span></p><pre><code class="language-python">//7.事件互動:滑鼠點擊按鈕會切換資料集
function click_me(){
[data1, data2]=[data2, data1]; //交換資料集
//矩形的動畫
svg.selectAll('rect')
.data(data1)
.transition() //8.過渡動畫
.duration(2000) //8.過渡動畫:動畫延續時間
.delay((d,i)=>i*200) //8.過渡動畫:以各資料點的索引為準,讓不同資料點開始動畫的時間不一樣
.attr('y',d=>yScale(d)) //透過改變y軸座標值,增加動畫效果
.attr('height',d=>svgHeight-yScale(d));//透過改變矩形長度,增加動畫效果
//文字標籤的動畫
svg.select('.bars').selectAll('text') //選定長條圖中的文字元素,而非座標軸刻度的文字元素
.data(data1)
.transition()//8.過渡動畫
.duration(2000)//8.過渡動畫
.delay((d,i)=>i*200)//8.過渡動畫
.attr('y',d=>yScale(d))
.text(d=>d);
}
</code></pre><div class="raw-html-embed"><h3 id="heading5">參考資料</h3>
</div><p><span style="background-color:transparent;color:#000000;">呂之華(2018)。AI時代在網頁上資料視覺化:D3.js實作寶典。臺北市:佳魁數位。</span></p><p><span style="background-color:transparent;color:#000000;">Philipp K. Janert(2020)。D3實用指南:程式設計師和科學家的互動式圖形工具箱。臺北市:碁峰。</span></p><p> </p><p> </p>
animationOrD3