React: 使用 D3 實現可視化故事線

React: 使用 D3 實現可視化故事線

來自專欄極光日報

簡評:最近在研究數據可視化的內容,這篇文章提供了 SVG 動態布局一個不錯的思路。

本文目的是實現類似 Github PR 過程記錄線的效果。效果如下:

左側的是 SVG 元素, 右側是是動態長度的文本。

需要注意的問題:

  • SVG 的高度如何自適應右邊的文本高度。

我嘗試使用下面的布局來解決 SVG 自適應高度問題。

每個故事元素(每行),由 div 包含左側的 svg 和右側的 div 構成, svg 會繪製一個 icon 和一條垂直的線,右側的 div 包含一個不固定大小的文本。當內部的 div 擴大時會撐大外部的 div 進一步來影響 svg 的大小。

這樣看起來很棒??

但是這種方式限制比較大,很難對齊,而且你甚至無法想像當用戶調整瀏覽器瀏覽器大小時,會發生什麼情況。

我需要處理這幾個問題:

  • 無限制
  • API 簡單
  • 可以工作在任意高度的行上
  • 當行尺寸有變換時可以自適應
  • 可以方便的在不同布局中使用

解決方案

將所有的內容在 SVG 中渲染。使用 foreignObject 來支持右側文本的自動布局, 和使用 React ref 會掉來處理動態高度的問題。

如下圖所示:

  • 使用 <AccordionFlow> 渲染行。
  • <AccordionFlow> 會儲存一個已知或默認行高的數組,用於垂直定位。
  • <Row> 包含兩個 props: icon 和 content。
  • icon 用於渲染左邊的內容。
  • content 用於渲染右邊的內容和標題。
  • 高度更新回調會更新 <AccordionFlow> 中儲存的高度列表。
  • 進而觸發每行<Row>的 re-render 方法。
  • 當 content 有更新,也會通知 <Row > 的更新高度。

具體的效果如下:

https://www.zhihu.com/video/989786388660826112

你們要的源碼?? 鏈接。

現在來具體看一下源碼:

先構建一個 array 用於儲存所有類型的 icon,我們將 DynamicContent 封裝在 函數中,以便於可以方便的更新右側的內容。

// index.js prep data const icons = [<Circle />, <Rectangle />, <Triangle />], flowData = d3range(10).map(i => [ icons[i % 3], contentUpdated => ( <DynamicContent title={`Row ${i}`} contentUpdated={contentUpdated}> {d3range(10) .slice(0, i) .map(() => faker.lorem.paragraph())} </DynamicContent> ) ]);

將所有的內容放到 svg 中渲染。

// index.js <svg width_="600" height="2240"> <AccordionFlow data={flowData} /> </svg>

// AccordionFlow.jsclass AccordionFlow extends React.Component { defaultHeight = 50; state = { heights: this.props.data.map(_ => this.defaultHeight) }; render() {...}}

AccordionFlow 內包含 state.heights 用於儲存所有行的高度。默認每行為 50,當行的內容發生變化的時候回通過 reportHeight 來進行更新具體行高。

// AccordionFlow.js// Row 用於渲染 icon 和 content, 並且處理事件和具體的邏輯。 <Row {...} reportHeight={height => { let tmp = [...heights]; tmp[i] = height !== undefined && height > this.defaultHeight ? height : this.defaultHeight; this.setState({ heights: tmp }); }} />// 當內容改變時可以通過this.props.reportHeight(element.getBoundingClientRect().height); // 來動態修改高度

詳細代碼可以參考源碼。

原文:Build an animated pure SVG dynamic height accordion with React and D3

推薦:這就是我想要的 VSCode 插件!

極光日報,極光開發者旗下媒體。

每天導讀三篇英文技術文章。


推薦閱讀:

Vue和React的使用場景和深度有何不同?
在RN在使用字體圖標
React中無狀態組件是無法通過ref獲取的
如何理解 Vue.JS 2016年的 github 星標( Star )數量增長超過 React ?
React.createClass中console.log(this)結果是Coustructor?

TAG:React | 可視化 | 數據可視化 |