最近正在學習數據可視化
, 這裏記錄一下一些心得與成果, 採用的技術是 (svg + react + d3)。 這種實現可視化方式本人我的感受超級不錯,若是你是有必定的基礎的同窗,強烈推薦一下。javascript
總體效果以下:java
這個是普通的速度儀表盤,有沒有開發太多的動態交互,惟一的交互是點擊圖片最上面的加速
與減速
就可以調整速度了。react
使用create-react-app建立一個新的項目,添加依賴d3
git
yarn add d3
這裏速度範圍是[0, 200], 對應角度範圍我的設置是[150, 390], 很明顯這是一個線性比例尺。速度間隔是2
。代碼以下github
const scale = d3.scaleLinear().domain([0, 200]).range([150, 360 + 30]) const ticks = scale.ticks(100) // 200 / 2 => 100
function Chart(props) { const { width, height, margin } = props return ( <svg width={width} height={height}> <g transform={`translate(${margin.left}, ${margin.top})`}> { props.children } </g> </svg> ) } ...... export default class Meter extends Component { ... render () { // config => {width: xxx, height: xxx, margin: xxx} return ( <div className={'container'}> <Chart {...config}> <g> <circle cx={0} cy={0} r={204} fill={'rgba(158, 158, 158, .4)'}></circle> <circle cx={0} cy={0} r={196} fill={'#FFF'}></circle> <circle cx={0} cy={0} r={200} fill={'transparent'} stroke={'#000'}></circle> </g> </Chart> </div> ) } }
上面實際上是繪畫了三個圓, 利用SVG後面的繪製的圖畫,會覆蓋前面的圖畫的特性。先畫最外面,而後最裏面,最後中間的圓。 就把最外層的圈給描繪出來了,效果以下:
app
接着上面的代碼結構,咱們開始刻畫刻度尺dom
...... export default class Meter extends Component { ... render () { // config => {width: xxx, height: xxx, margin: xxx} return ( <div className={'container'}> <Chart {...config}> <g> <circle cx={0} cy={0} r={204} fill={'rgba(158, 158, 158, .4)'}></circle> <circle cx={0} cy={0} r={196} fill={'#FFF'}></circle> <circle cx={0} cy={0} r={200} fill={'transparent'} stroke={'#000'}></circle> </g> <g fill={'transport'} stroke={'#000000'}> { ticks.map((tick) => { let IS_20_TIME = tick % 20 === 0 let title = IS_20_TIME ? <text x={160} dominantBaseline={'middle'} textAnchor={'end'}>{tick}</text> : '' return ( <g transform={`rotate(${scale(tick)})`} key={tick}> <path d={`M165, 0L185,0`} strokeWidth={IS_20_TIME ? 3 : 1}></path> {title} </g> ) }) } </g> </Chart> </div> ) } }
這裏刻畫刻度尺,個人思路很簡單,刻度尺是對速度大小的描述,而速度跟角度又是線性相關,反過來,速度對應角度。因此,我只是須要根據速度所對應的角度,而對水平刻度進行旋轉便可。效果你們能夠看到:
svg
指向針其實就是一個圓 + 三角形的組合,代碼以下:學習
<circle cx={0} cy={0} r={10} fill={'#'}></circle> <path d={`M-20, 5L-20, -5L130, 0Z`} transform={`rotate(150)`}> <animateTransform ></animateTransform> </path>
上面本人實現的比較粗糙,你們能夠把這個封裝成一個shape
, 之後能夠直接複用的,後面若是須要旋轉,能夠經過<g>元素來實現。 this
到這一步,一個簡單的儀表盤就初具原型了
指針的轉動是根據速度來的,因此咱們須要先定義一個speed
的狀態。
constructor(props) { super(props) this.state = { speed: 0 } }
接下來,咱們須要把speed映射到指針上面。怎麼處理呢
還記得前面定義的scale
,這個是一個線性比例尺,經過它咱們可以獲取不一樣速度對應的角度
咱們把上面的指向針代碼進行改造
const {speed} = this.state ...... <circle cx={0} cy={0} r={10} fill={'#'}></circle> <path d={`M-20, 5L-20, -5L130, 0Z`} transform={`rotate(${scale(speed)})`}> <animateTransform ></animateTransform> </path>
這樣咱們設置不一樣的speed就能在頁面控制指針指向不一樣的刻度尺。
所謂的速度標識區間,其實就是幾段圓弧,經過不一樣的顏色來告知進入不一樣的速度區間。
這裏我對圓弧進行了封裝,底層經過d3
的arc方法來建立圓弧。
function LArc(props) { const { start, end, color } = props let _arc = d3.arc()({ innerRadius: 165, outerRadius: 185, startAngle: Math.PI * 2 * (scale(start) + 90) / 360, endAngle: Math.PI * 2 * (scale(end) + 90) / 360 }) return ( <path d={_arc} fill={color}></path> ) }
這裏其實還有一個問題,就是須要先加載速度標識區間,而後再去添加刻度尺,否則標識區間會覆蓋刻度尺(切記)。
這樣一個基本速度儀表盤就出來了
若是你能明白上面的實現思路,我以爲你能夠本身實現一個時鐘
了
若是你想了解更多:好比指示器如何實現的
請參考
https://github.com/cookhot/i-... (本人會在裏面不按期增長新圖表哦)