最近正在学习数据可视化
, 这里记录一下一些心得与成果, 采用的技术是 (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-... (本人会在里面不按期增长新图表哦)