使用 React 製作資料圖表 — D3 與其他三種方案

李至青
Visually Lab
Published in
8 min readDec 30, 2019
Photo by Kelly Sikkema on Unsplash

圖表是一個常見的網頁 component ,根據需求的不同,有時在實作上會相當複雜,當團隊以 React 作為網頁的主要框架時,挑選適合的策略去實作圖表是重要的課題,在這篇文章中會以不同的方式實現一個簡單的長條圖,討論這個議題:

  • 當你只需要一個很簡單的圖表,使用 React。
  • 當你需要一個很簡單的圖表跟一點動畫,沒有客製化需求,用 RechartsvictoryEchart
  • 當你有客製化圖表的需求,用 React + D3。如果需要 D3 操作 DOM 的功能,使用 React + vx。

文中所使用的程式碼圖片經過簡化,完整的程式碼在文末可以看到。

當你只是需要一個常見的圖表

當你需要的是製作一個圓餅圖、長條圖、折線圖,它不需要特別絢麗的外觀,你可以考慮使用直接使用 React 實作一個簡單的圖表,或者根據你的需求,挑選現成的圖表 Library。

使用 React 實作一個簡單的圖表

透過 React JSX 的語法,可以很容易將資料 mapping 到元件的 style,只要將數值 mapping 到 css 長寬,那就是一個簡單的長條圖了。

src/ReactChart.tsx

挑選一個符合需求的圖表 Library

當你想要一點絢麗的效果,且不想要自己來實作,我推薦使用三個 Library,RechartsVictoryEchart

他們都兼具了三個優點:

  • Responsive:支援響應式網頁
  • built-in animation:內建支援圖表動畫
  • customize:支援一定程度的客製化

此外, Victory 與 Rechart 都是以 React 寫成。

以下由 Library 所提供的參數複雜度為標準, 依強大程度從小到大排序:

  • Recharts:動畫活潑生動,但自訂性稍差
  • Victory:設定較複雜,熟悉 API 後,可以做一定程度的客製化
  • Echart:功能強大,可以修改相當多樣的參數,搭配 React 使用需要使用封裝的版本(或是自己封裝)

下方我以 Recharts 實作的長條圖程式碼,可以看到程式碼非常的簡潔,馬上就能夠得到一個可用的長條圖。

src/Rechart.tsx

但如果需要將這個長條圖修改成與上一個例子一模一樣,仔細看過文件一遍,你會發現不知從何做起,有非常多的問題存在。文件上有調整 layout 方向的 api,但實際上運作的跟想像不同,標籤的文字因為空間不足而自動隱藏了,該如何調整? 圖表是一個相當複雜的 component ,即使 Recharts 是一個超過一萬顆星的 Library 仍存在許多問題。

使用 Library 最需要注意的是在專案中有沒有必須要客製化的需求。通常修改現成的 Library 是相當耗時費力,事倍功半的過程,如果有客製化的需求,得要好好權衡 使用這個 Library 省下的開發時間 去掉 客製化所花費的修改 ,究竟有沒有比較划算?

如果沒有,可以參考下文,使用 React 搭配 D3/vx 。

當你需要實作客製化資料圖表

當客戶說:要繪製一張市面上產品的散布圖

  • 把每個產品以發售公司為 x 軸
  • 發售時間為 y 軸
  • 銷售量為資料點大小和透明度
  • 資料點上需要標註發售公司的第一個字
  • 同時希望可以比照設計稿實作樣式

如果是這樣的需求,採用現成圖表 Library 然後做修改成本太高,必須做一個客製化圖表。但如果沒有現成的圖表,有沒有做圖表的工具包,讓我們至少可以不用從頭開始?

有,我們用 D3.js

D3 (Data-Driven Documents) 是最知名的一個 javascript 資料視覺化 (data visualization) 函式庫,他提供了許多在製作資料圖表時使用的工具函式。當然,他也可以搭配 React 使用。

如何整合 React 與 D3

D3 本身是可以獨立使用的 Library,並非必須搭配 React 使用。因此在搭配 React 使用,當兩者都必須操作 DOM 時,就會在 DOM 的操作上會有衝突,可能造成 DOM 不同步,出現預期外的變化。

有兩個策略解決:

  1. 必須要使用 D3 操作 DOM 時,透過 React 傳出 DOM Ref 傳遞給 D3 操作
  2. 避免使用 D3 操作 DOM,也就是避免使用以下程式碼

此列表參考自 How (and why) to use D3 with React

在這裏我傾向 2. ,避免使用 D3 操作 DOM,因為同時透過 D3 與 React 操作 DOM 會讓程式難以閱讀、管理,如果有需求必須使用到上列的那些功能,可以使用下文介紹的 vx ,這是將 d3 與 React 整合後的函式庫。

那為什麼不直接使用 vx 就好呢?雖然 vx 目前提供了許多的 D3 功能,但還在持續發展中,文件並不是非常齊全。如果已經有使用過 D3 經驗,直接使用 D3 搭配 React 會更順利。

除了操作 DOM 以外,D3 還提供什麼功能?D3 還可以處理你的資料

例如,使用 d3-scale 把 data mapping 成圖表的視覺屬性。

src/ReactWithD3Chart.tsx

在這段程式碼中,數值越靠近 60 就會回傳越靠近橘色,數值越靠近 120 就會回傳越靠近藍色。此外因為是使用 React 操作 DOM,我可以透過 scale function 取得任何一個 Bar 的位置,在任何一個元件上監聽 Event,我們擁有相當大的自由度去操作整個圖表。

在長條圖上以顏色反應數值高低

React + vx 打造你的客製化圖表

vx (visualization components) 是由 Airbnb 工程師所推出的專案,整合 React 操作 DOM 的優勢,加上 D3 實作 data visualization 的強大功能,是一系列可以重複使用的 low-level 視覺化 component。

vx is a collection of reusable low-level visualization components. vx combines the power of d3 to generate your visualization with the benefits of react for updating the DOM.

使用 React 和 vx 來重新做一次上方的圖表

使用了在 vx 中提供的 scale, Bar , Axis 跟上個例子比起來,透過 vx 我們可以透過 React 整合 D3 原本操作 DOM 的功能,例如產生座標軸 (Axis),也不用自己寫 Bar ,並且提供了相當 low-level 的參數設定,得以做到在快速產生圖表的同時,也保有客製化的空間。

src/VxChart.tsx

因為是透過 React 控制 DOM ,如果想要動畫,也可以整合任何一個 React 動畫 Library,例如 react-motion, react-spring。透過 React + vx 實作圖表的策略,我們同時擁有了 D3 的強大功能,也把客製化圖表的自由度找回來了。

使用 React + vx 在使用 D3 的功能同時,還原出一模一樣的圖表

回顧整理

當你只需要一個很簡單的圖表,使用 React。

當你需要一個很簡單的圖表跟一點動畫,沒有客製化需求,用 Recharts, victory, eCharts

當你有客製化圖表的需求,用 React + D3。如果需要 D3 操作 DOM 的功能,使用 React + vx。

程式原始碼

--

--