---
slideOptions:
mouseWheel: true
width: 100%
height: 90%
margin: 0.1
minScale: 1.0
maxScale: 2.0
loop: true
---
# D3.js基礎圖形繪製
黃安聖(andy)
andy@kyosei.ai
###### tags: `D3.js`
----
請先開啟程式碼同步網站
https://instacode-live.herokuapp.com/channel/andy
----
## D3.js
Data-Driven Documents
https://d3js.org/
----
## 引用D3.js
可從CDN.js網站中搜尋d3
https://cdnjs.com/
----
將D3.js Library的連結放入HTML的script標籤已啟用
```htmlmixed=
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.15.0/d3.min.js"></script>
```
----
## 繪製一個簡單的SVG圖形
SVG(Scalable Vector Graphics)
----
### 定義SVG邊界
```javascript=
// 將圖形儲存以利後續使用
const svg = d3
// 選擇一個畫面上元素作為容器
.select('#chart')
// 設定要新增的標籤名稱
.append('svg')
// 設定svg的width屬性
.attr('width', 600)
// 設定svg的height屬性
.attr('height', 400)
```
----
### 在svg上繪製一個矩形
```javascript=
svg
// 在指定元素(svg)上放置一個矩形
.append('rect')
// 設定寬度
.attr('width', 50)
// 設定高度
.attr('height', 100)
// 設定所在座標
.attr('x', 0)
.attr('y', 0)
// 設定顏色
.attr('fill', 'royalblue');
```
----
### 在svg上繪製一個圓形
```javascript=
svg
// 在指定元素(svg)上放置一個圓形
.append('circle')
// 設定半徑
.attr('r', 50)
// 設定圓心位置
.attr('cx', 200)
.attr('cy', 200)
.attr('fill', 'tomato');
```
----
除此之外你也可以透過d3直接控制HTML標籤
```javascript=
d3
.select('#box1')
// 改變元素內部的html內容
.html('我是box1')
```
----
甚至是標籤的CSS屬性
```javascript=
d3
.select('#box1')
.html('我是box1')
.style('background-color', 'tomato')
.style('width', '200px')
.style('height', '100px')
```
----
### 陣列資料繪製
----
陣列資料可能產生的問題:
==資料數量與元素(DOM)不相等==
----
當畫面上有多個元素
```htmlmixed=
<div id="barContainer">
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
</div>
```
----
選取元素的容器
```javascript=
const barContainer = d3.select('#barContainer')
```
----
準備資料
```javascript=
const data = [10, 20, 30]
```
----
繪製圖型
```javascript=
barContainer
.selectAll('.bar')
.data(data)
.style('width', function (d) {
return `${d}%`;
})
```
----
圖形可被成功繪製

----
但若是資料的數量有變動將會發生什麼事?
```javascript=
const data = [10, 20, 30, 40, 50]
```
----
圖形將會缺少追加的資料,原因在於在HTML內==缺少了對應的元素==

----
#### 解決方式
選擇容器
```javascript=
const barContainer = d3.select('#barContainer')
```
----
準備資料
```javascript=
const data = [10, 20, 30, 40, 50]
```
----
選擇容器內的目標.bar並配對資料
```javascript=
const bars = barContainer
// 選擇容器內的.bar
.selectAll('.bar')
.data(data)
```
----
繪製每個長條圖的資料
```javascript=
bars
// 當資料與DOM初次配對完成後
.enter()
// 放入div
.append('div')
// 賦予class="bar"
// 讓上述選擇條件可選擇
.attr('class', 'bar')
// 設定CSS寬度
.style('width', function (d) {
return `${d}%`;
})
```
----
### 課堂練習
將陣列資料轉換為圖表
```javascript=
const data = [12, 2, 5, 6, 7, 18];
```
----
選擇SVG容器並填入SVG
```javascript=
// 將圖形儲存以利後續使用
const svg = d3
// 選擇一個畫面上元素作為容器
.select('#chart')
// 設定要新增的標籤名稱
.append('svg')
// 設定svg的width屬性
.attr('width', 600)
// 設定svg的height屬性
.attr('height', 400)
```
----
帶入資料
```javascript=
const circles = svg
// 選擇circles裡面的circle
.selectAll("circle")
// 在每個circle內帶入data裡的每筆資料
.data(data);
```
----
透過資料數據顯示圖形
```javascript=
circles
// 初次將資料帶入元素內
.enter()
.append('circle')
.attr('r', function (d, i) {
// 值可帶入一個function,並且自動帶有兩筆輸入
// d: 資料 , i:索引(排序)
return d;
})
.attr('cx', 10)
.attr('cy', 50)
.attr('fill', 'tomato');
```
----
### 課堂練習
1. 將圖面中的圓形由左至右排列
2. 設定填色條件,資料大於10填入#f85a40,反之則填入#ffc845
----
### 設定mouseenter事件
```javascript=
.on('mouseenter', function(d, i) {
// 游標進入事件
});
```
----
### 取得事件參數
透過==d3.event==取得事件參數
```javascript=
.on('mouseenter', function(d, i) {
console.log(d3.event);
});
```
----
也可整合其他滑鼠事件
|事件名稱|敘述|
|-|-|
|mouseenter|游標進入元素|
|mouseleave|游標離開元素|
|mousemove|游標在元素移動|
----
### 課堂練習
1. 設計一個標籤用以顯示該圖型背後的數值
2. 於滑鼠游標碰觸圖型時顯示標籤
----
### 載入JSON檔案
```javascript=
d3.json('檔案名稱.json')
.then(function(data){
// 載入成功
})
.catch(function(err){
// 載入失敗
})
```
----
### 以政府公開資料為例
細懸浮微粒資料(PM2.5)
https://data.gov.tw/dataset/34827
----
### 課堂練習
1. 繪製新北市各區PM25指數
2. 滑鼠游標碰觸後可顯示資料標籤