D3 + p5.js 筆記 - Area Chart

  1. 1. 程式碼說明
    1. 1.1. preload
    2. 1.2. setup
    3. 1.3. draw

banner

程式碼說明

以下主要說明部份的坑以及重點,請配合 GitHub 的 js 程式碼服用。

preload

ctx.loadTable 是非同步處理,最普通的作法就是指定給宣告的變數

1
dataset = ctx.loadTable('area.tsv', 'tsv', 'header', callback)

但 preload 請求的資料,在 setup 函式裡才可以使用,如果直接在 preload 裡 console 出來是沒有東西的,但你可以宣告 callback function 來對資料預先處理。

不得不說,p5.js 的 loadTable 幫你整理資料這件事實在非常多餘,幫你把資料整理好了,但你卻沒法直接取出完整的 json 陣列資料。

而官方提供的 API 中,最接近的 getObject 取出來的樣子是:

1
2
3
4
5
{
'0': data1,
'1': data2,
'2': ...
}

WTF

setup

主要就是在這邊讓 D3 計算縮放後的刻度、座標,由於 draw 的函式預設會刷新畫布,所以能夠事先計算的部份都盡量放在 setup 裡。

1
2
3
4
5
6
7
8
9
10
11
12
xScale = d3.time.scale()
.domain(d3.extent(dataset, d => d.date))
.range([ chartX, chartWidth + chartX ]);

xTickFmt = xScale.tickFormat(date => date.getFullYear());
xLabels = xScale.ticks(d3.time.year);

yScale = d3.scale.linear()
.domain([ 0, d3.max(dataset, ({ close }) => close) ])
.range([ chartHeight + chartY, chartY ]);

yLabels = yScale.ticks(10);

domainrange,簡單來講就是從資料以及指定的畫布大小來決定畫布上的座標,省去寫縮放程式碼的麻煩。

X 軸是以時間為刻度,用 D3 的 ticks 設定為以年份劃分刻度,Y 軸則設定為分割成 10 個座標。ticks 最後會產生一串陣列,裡面存放刻度的標籤名稱,用 yScale(data) 可以取得該筆資料在 Y 軸的位置。

draw

p5 預設會重複畫 draw 裡的內容,可以在 setup 補上 noLoop 來關掉自動重繪,否則也要在 draw 的開頭使用 clean 來清掉畫布,否則畫布上的元素會重複疊加上去。另外畫布的背景預設為透明,故需先畫上指定顏色的背景,否則存成圖檔時會是透明背景。

這邊注意的一點是,除了 strokefill 等等會影響畫筆(ctx)行為之外,有些則是會影響整個畫布的,比如 rotate 會把要畫的圖層整個旋轉,結尾要使用 resetMatrix 調回原狀,或是用 pushpop 來暫存原本的狀態。

比如前面設定 fill 的顏色,但是在 push 與 pop 之間使用 noFill 時,當 pop 出來後畫筆依舊是 fill 的狀態。