1 of 37

D3.js

RD讀書會技術學習分享

上德 20190816

2 of 37

SVG的使用方式(補充)

SVG格式為XML的一種,在網頁中使用SVG圖檔有兩種方式:

1. 使用<img src="img.svg">標籤連結.svg檔案

2. 使用<svg>…一堆標籤…</svg>標籤

3 of 37

SVG繪製流程(方法一)

苦學三個月

Coding svg標籤

畫出普通蘋果

4 of 37

SVG繪製流程(方法二)

畫出金蘋果

Neil大大打開illastrator

跪求Neil大大

5 of 37

那如果不但要畫蘋果�又要隨著數據改變蘋果的樣子�蘋果還要會動,還要跟你互動呢…?��

6 of 37

今天會介紹到D3.js的這些功能

  • Data-Join
  • Selection及元素操作
  • 比例尺
  • 色彩系統
  • 座標軸
  • 動畫
  • 繪圖產生器
  • Layout

7 of 37

學習資源

  • 資源不是很多,目前繁中的書都是以v3.x版的為主,簡中可找到幾本v4.x的書。

  • 官網中文文件也是v3.x版的,英文文件才會是最新版的API,但官網文件很像在看字典不太容易閱讀。

  • 網路文章(中文)也是以v3.x的為多,有幾個不錯的文章/網站:

D3.js新手開發基本圖表

https://ithelp.ithome.com.tw/articles/10201584

寫的不錯的部落格

https://www.oxxostudio.tw/search-results.html?s=d3

d3.js 教程

http://www.tastones.com/zh-tw/tutorial/d3js/

https://d3indepth.com/

Kuro大簡短的入門介紹 - D3.js 圖表優化二三事

https://www.youtube.com/watch?v=mEkWpwXE6oo

資料視覺化部落格

http://blog.infographics.tw/

8 of 37

版本差異

  • v3及v4以上版本多數API不相容,主要在名稱上的差異比如:

v3: d3.scale.linear()

v4↑: d3.scaleLinear()

  • v4重要更新:
    • 開始支援Canvas
    • 新增js module版本(可由npm引入)
    • 新增模組化的libarary(可只引入部份功能以節省空間)

  • v5重要更新:
    • 新的色彩系統
    • ajax改用es6的fetch及promise(不相容ie)

  • 今天的內容將以v5為主

9 of 37

Data Driven Documents

D3.js

Data

圖表元素

Selection

(Data Join)

資料運算函式

圖型運算函式

互動

動畫

10 of 37

選擇器

  • 選擇單個element

d3.select('selector')

  • 選擇多個element

d3.selectAll('selector')

*tip: 當成jquery的$('selector')來用即可

11 of 37

Data-Join的兩個方法

  • 單筆資料加入多個元素(不常用)

selection.datum()

  • 多筆資料加入多個元素

selection.data()

12 of 37

Data-Join的三種概念(Enter、Update、Exit)

  • Enter: 資料陣列長度大於元素數量,還不存在的元素稱為Enter(即將進入)
  • Update: 資料陣列長度等於元素數量的部份稱為稱為Update(即將更新)
  • Exit: 資料陣列長度小於元素數量,多餘元素的的部份稱為Exit(即將退出)

13 of 37

Data-Join常用的寫法

  • update、enter、exit以及merge的兩種寫法

https://codepen.io/cdpqdnvr/pen/VJwjPa

  • 一般圖表渲染不會只有一次(當更新資料時),所以Data-Join寫法要非常小心,不要造成不必要的「重覆運算」、甚至是更嚴重的「重覆渲染」(很容易發生,多寫幾次就知道訣竅)

14 of 37

單個元素操作

  • 設定元素的attribute

selection.attr('attribute-name', 'value')

  • 設定元素的Class

selection.classed('class-name', bool) // bool: true/false

  • 設定元素的style

selection.style('style-name', 'value')

*tip: 直接當jQuery寫就可以了

15 of 37

多個元素操作

  • 設定元素的attribute

selection.attr('attribute-name', function(data, index, nodes){

return 各別元素的value

})

  • 設定元素的Class

selection.classed('class-name', function(data, index, nodes){

return 各別元素true/false

})

  • 設定元素的style

selection.style('style-name', function(data, index, nodes){

return 各別元素的value

})

*tip: 直接當jQuery寫就可以了

16 of 37

自己計算座標來繪圖有點辛苦…

範例:

http://jsfiddle.net/upstairs0102/a1fku6ec/33/

此範例中的長條圖及數字,分別手動計算圖形的長寬以及座標,這樣有一些缺點:

  1. 程式可讀性低
  2. 繪圖邏輯環環相扣,每改一個參數所有東西都要跟著調整
  3. 圖型、文字(或者如果還有其他東西如刻度等)等每個都是各別計算,而不是共用同樣的函式

17 of 37

比例尺 - 線性比例尺(Linear Scale)

  • 連續資料對應到連續資料

18 of 37

比例尺 – 序數比例尺(Oridinal Scale)

  • 離散資料對應到離散資料

let scale = d3.scaleOrdinal()

.domain(['like', 'wow', 'ha', 'love', 'cry', 'angry'])

.range(['#de6868', '#b94141', '#81a7a6', '#aad0ac', '#5496b1', '#ffca72’])

scale('wow') // #b94141

19 of 37

實例 – 色彩系統

  • 色彩系統

https://github.com/d3/d3-scale-chromatic

離散型

連續型

  • 離散資料色彩對應範例

https://codepen.io/cdpqdnvr/pen/KjNLJQ

20 of 37

比例尺 – 序數點比例尺(Point Scale)

  • 離散資料對應到連續資料

let scale = d3.scalePoint()

.domain(['like', 'wow', 'ha', 'love', 'cry', 'angry'])

.range([0, 100])

scale(love) // 60

21 of 37

其他比例尺

其他還有一堆比例尺和各種不同的API搭配

  • d3.scaleLinear() − Constructs a continuous linear scale where we can input data (domain) maps to the specified output range.
  • d3.scaleIdentity() − Construct a linear scale where the input data is the same as the output.
  • d3.scaleTime() − Construct a linear scale where the input data is in the dates and the output in numbers.
  • d3.scaleLog() − Construct a logarithmic scale.
  • d3.scaleSqrt() − Construct a square root scale.
  • d3.scalePow() − Construct an exponential scale.
  • d3.scaleSequential() − Construct a sequential scale where output range is fixed by interpolator function.
  • d3.scaleQuantize() − Construct a quantize scale with discrete output range.
  • d3.scaleQuantile() − Construct a quantile scale where the input sample data maps to the discrete output range.
  • d3.scaleThreshold() − Construct a scale where the arbitrary input data maps to the discrete output range.
  • d3.scaleBand() − Band scales are like ordinal scales except the output range is continuous and numeric.
  • d3.scalePoint() − Construct a point scale.
  • d3.scaleOrdinal() − Construct an ordinal scale where the input data includes alphabets and are mapped to the discrete numeric output range.

22 of 37

座標軸

  • 有四種,分別為上下左右的標軸 axisLeft, axisRight, axisTop, axisBottom

let axis = d3.axisBottom()

.scale(scale) // 放入比例尺

// 設定刻度文字格式

axis.tickFormat(function(d){

return d

})

// 設定刻度分段數量

axis.ticks(number)

// 指定特定的刻度(和asix.ticks()不能共用)

axis.tickValues([value1, value2, value3])

23 of 37

實例

  • X軸刻度用d3.scaleLinear()計算(離散資料)
  • Y軸刻度用d3.scaleOrdinal()計算(連續資料)

24 of 37

動畫 -過渡(transition)

  • 建立過渡有兩種方式:d3.transition和selection.transition。一般transition()會再搭配(非必要)以下三種方法:

transition.delay(ms) 延遲開始的時間,單位是毫秒

transition.duration(ms) 過渡的持續時間

transition.ease(type) 過渡樣式,包含linear、cubic、elastic、back、bounce…等

  • ease種類

https://bl.ocks.org/d3noob/1ea51d03775b9650e8dfd03474e202fe

25 of 37

transition範例

範例1:在<svg>中加入一個矩形,從座標(10,10)位移到(50,50)

http://jsfiddle.net/upstairs0102/gmLcbr2j/

範例2:加入一個矩形,從寬度100過渡為寬度300,此外還增加ease()、過渡樣式設定為”bounce”

http://jsfiddle.net/upstairs0102/L4gj56oa/

26 of 37

動畫 - tween和interpolate的搭配

  • 差值器(interpolate)
  • 實例:數字動畫

https://jsfiddle.net/upstairs0102/vk40m18b/

27 of 37

實作 – 繪製長條圖

實例:以前面實作的刻度加上長條圖,並使用transition()來做動畫

https://codepen.io/cdpqdnvr/pen/ymoQVj

28 of 37

顏色(1)

D3的顏色有RGB和HSL兩種方法,可以互相轉換。

d3.rgb(r,g,b) 以rgb作參數,範圍都為0~255

d3.rgb(color) 輸入顏色字串,可用多種的格式包含"rgb(255,255,255)"、"hsl(120,0.5,0.5)"、"#ff0000"、"red"

rgb.brighter(k) 顏色變更亮

rgb.darker(k) 顏色變更暗

rgb.hsl() RGB轉換為HSL物件

rgb.toString() RGB物件轉字串,輸出格式為"#ff0000“

d3.hsl(h,s,l) h為色相(Hue)範圍0~360、s為飽和度(Saturation)範圍0~1、l為亮度(Lightness)範圍0~1

d3.hsl(color) 輸入顏色字串

也可以使用brighter()、darker()、rgb()(轉換為rgb)、toString()方法

29 of 37

顏色(2)

要計算介於兩個顏色之間的顏色,可以使用內插(Interpolation),使用方法為

d3.interpolate(a,b)

30 of 37

線產生器d3.line() (1)

31 of 37

線產生器d3.line() (2)

32 of 37

區域產生器d3.area()

  • 同樣也是可以搭配curve()函式

33 of 37

弧產生器d3.arc()

d3.arc() 建立弧產生器,回傳可使用的函式

src.innterRadius() 內半徑

src.outerRadius() 外半徑

src.startAngle() 起始角度

src.endAngle() 結束角度

角度的單位是π,0°時是0π、180°是1π、360°是2π,可以使用Math.PI來計算。

34 of 37

實作 – 繪製圓餅圖

35 of 37

Layout

  • D3提供的各式圖型產生器是用來繪製基本的svg圖型,但是在更複雜的圖表型式時,就需要使用D3更高階的繪圖函式來計算及操作繪圖所需的資料。

  • 不過D3 v4.0之後就沒有再使用「Layout」這個名稱來統稱這些函式,而是以各別的函式的功能來做歸類,比如「熱力圖」(d3.contour)、「力導向圖」(d3.force)…等

36 of 37

Layout之很簡單範例 – �使用d3.pie()產生所需資料繪製圓餅圖

塞入d3.arc()

(見前面範例)

37 of 37

總結

  • D3的學習感覺是一條漫漫長路,每次要做一個新的東西就又要重新學習,要不斷的查資料和實驗。

令人髮指的

Api list