监控领域中的Echarts 定制化封装之ConnectCharts和GridCharts
接上一篇Echarts 定制化封装之dataset,这次来聊一聊监控领域中的echarts封装。主要服务于dashboard这个模块。在监控、分析领域,是有查看同一时间各项指标的数据需求的,比如某台主机CPU的使用率、内存展示情况等有关联关系的“黄金指标”。如果把这些指标放在同一个图中问题很简单,如果放在不同图(组件)中,想查看同一时间怎么处理呢。对,你猜到了,就是不同图表之间的联动。及个性化定制dashboard需求可拖拽、缩放等,本文就从这两个方面进行。
代码地址:https://github.com/wlc534/react-r3-saga
可联动的ConnectCharts
看到业绩标杆产品,各种酷炫的dashboard可拖拽、可缩放、可联动的图表。好奇心驱使去研究源码,很快发现老外的产品大部分是基于highcharts或者D3。但我们WiseAPM图表还是Echarts。接下来就自己动手。
对于一个库,最好资料就是官方文档。很快就在echarts官网API中查到echarts.connect,文档的完整性方面还是要给ec点赞。
echarts.connect Function (group:string|Array) 多个图表实例实现联动。 参数:
示例: // 分别设置每个实例的 group id chart1.group = 'group1'; chart2.group = 'group1'; echarts.connect('group1'); // 或者可以直接传入需要联动的实例数组 echarts.connect([chart1, chart2]);
|
有了官方的支持,接下来的事情就好办了,先上代码。为了便于理解,代码中就两个echarts进行联动。
import React, {Component} from 'react'; import ReactEcharts from 'echarts-for-react'; import echarts from 'echarts' import './WiseCharts.css' const getKeys = data => Object.keys(data);
export default class MoreWiseCharts extends Component { static defaultProps = { height: 400, title: '默认名称', type: 'line' };
constructor(props) { super(props); this.getOption = this.getOption.bind(this); } componentDidMount(){ const echartsInstanceOne=this.echarts_react_one.getEchartsInstance() const echartsInstancetwo=this.echarts_react_two.getEchartsInstance() echarts.connect([echartsInstanceOne,echartsInstancetwo]) }
getOption() { setTimeout(() => { console.log(this.echarts_react) }, 1000); const [first, ...legendData] = getKeys(this.props.data); const legendDataArr = []; let legendTrStr = ''; legendData.forEach(item => { legendDataArr.push({ name: item, icon: 'circle' }); legendTrStr += `<td>${item}</td>`;
});
return { title: { text: this.props.title, }, tooltip: { trigger: 'axis' }, legend: { bottom: '3%', type: 'scroll', data: legendDataArr },
dataset: { source: this.props.data }, grid: { left: '3%', right: '4%', bottom: '10%', containLabel: true },
toolbox: { show: true, feature: { dataZoom: { yAxisIndex: 'none' }, dataView: { readOnly: false, optionToContent: function otc(opt) { const timeArr = Object.values(opt.dataset[0].source); let table = `<table style="width:100%;text-align:center;background-color: #f5f5f5" class='reference'><tbody><tr> <td>时间</td>${legendTrStr} </tr>`; for (let i = 0, l = timeArr[0].length; i < l; i += 1) { let tdElm = ``; for (let j = 1; j < timeArr.length; j += 1) { const element = timeArr[j][i]; tdElm += `<td>${element}</td>`; } table += `<tr><td>${timeArr[0][i]}</td>${tdElm} </tr>`; } table += '</tbody></table>'; return table; }, }, magicType: { type: ['line', 'bar'] }, restore: {}, saveAsImage: {} }
}, xAxis: { type: 'category', boundaryGap: false, }, yAxis: { type: 'value' }, series: [...legendData].fill({ type: this.props.type }), color: [ '#FF9C6E', '#FFC069', '#95DE64', '#5CDBD3', '#69C0FF', '#85A5FF', '#B37FEB', '#FF85C0'
] }; } render() {
return ( <div style={{height:800,width:900,display:'flex'}}> <ReactEcharts option = { this.getOption() } style = { { height: '350px', width: '60%' } } ref={(e) => { this.echarts_react_one = e; }} className = 'react_for_echarts' / > <ReactEcharts option = { this.getOption() } style = { { height: '350px', width: '60%' } } ref={(e) => { this.echarts_react_two = e; }} className = 'react_for_echarts' / > </div> )} } |
上面最核心的代码如下:
componentDidMount(){ const echartsInstanceOne=this.echarts_react_one.getEchartsInstance() const echartsInstancetwo=this.echarts_react_two.getEchartsInstance() echarts.connect([echartsInstanceOne,echartsInstancetwo]) }
<ReactEcharts option = { this.getOption() } style = { { height: '350px', width: '60%' } } ref={(e) => { this.echarts_react_one = e; }} className = 'react_for_echarts' / > <ReactEcharts option = { this.getOption() } style = { { height: '350px', width: '60%' } } ref={(e) => { this.echarts_react_two = e; }} className = 'react_for_echarts' / >
|
在组件渲染的生命周期函数componentDidMount()拿到想联动echarts 实例。之后传入echarts.connect()中,就能实现联动。此处用到React中ref获取到真实DOM元素。不理解的请自行官网。
问题:
联动效果不够优雅,tooltip不是完全的同步。和基于D3封装联动有差距。
可拖拽 、可缩放的GridCharts
拖拽、缩放的原理一般都是监听鼠标事件利用clientX和 clientY 进坐标的计算,结合CSS3的transform 变换。这块已经有大牛写好,我们就拿过来用。它就是react-grid-layout。https://github.com/STRML/react-grid-layout 用到该技术的项目还是挺多。
特点:
|
Projects Using React-Grid-Layout
代码:
import React, {Component} from 'react'; import WiseCharts from './WiseCharts' import GridLayout from 'react-grid-layout'; import '../../node_modules/react-grid-layout/css/styles.css' import '../../node_modules/react-resizable/css/styles.css' const data={ week: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], '邮件营销': [120, 132, 101, 134, 90, 230, 210], '联盟广告': [220, 182, 191, 234, 290, 330, 310], '视频广告': [150, 232, 201, 154, 190, 330, 410], '直接访问': [320, 332, 301, 334, 390, 330, 320], '搜索引擎': [820, 932, 901, 934, 1290, 1330, 1320], } class GridCharts extends Component{ render() { // layout is an array of objects, see the demo for more complete usage var layout = [ {i: 'a', x: 0, y: 0, w: 8, h: 2, }, {i: 'b', x: 0, y: 0, w: 3, h: 2, minW: 2, maxW: 4}, {i: 'c', x: 3, y: 0, w: 5, h: 2}, {i: 'd', x: 3, y: 0, w: 5, h: 2} ]; var style={background:'#ccc',border:'1px solid black'}; return ( <div style={{backgroundColor:'aliceblue',width:'70%',height:'80%'}}> <GridLayout className="layout" layout={layout} cols={12} rowHeight={130} width={1200}> <div key="a" style={style}> <WiseCharts type='line' width='100%' height='100%' title='多曲线图' data={data}/> </div> <div key="b" style={style}> <WiseCharts type='pie' width='100%' height='100%' title='饼图' data={data}/> </div> <div key="c" style={style}> <WiseCharts type='line' width='100%' height='100%' title='多曲线图' data={data}/> </div> <div key="d" style={style}> <WiseCharts type='line' width='100%' height='100%' title='多曲线图' data={data}/> </div> </GridLayout> </div> ) } } export default GridCharts; |
此时我们定制出自己的可拖拽 、可缩放的eCharts。
问题:
- GridCharts中WiseCharts props 中width='100%' height='100%'要进行这样设计,就能自动适应。
- 用了react-grid-layout,其中对echarts的操作就失效了。鼠标事件优先被react-grid-layout捕获到。
总结
以上就是ConnectCharts和GridCharts全部内容,功能基本实现,还有很多细节需要优化。
数据处理中感官认识依次友好是:普通数据<动态数据<静态图表<动态图表 这是数据可视化魅力!
项目代码地址:https://github.com/wlc534/react-r3-saga
最后还是要打一波广告的,平安科技集团运营管理部监控平台团队持续招人【前端岗位、运营岗位、算法岗位……】,如果想和我们一起打造极致的企业级全链路端到端监控平台,欢迎把简历投递到 WULIANGCHEN511@pingan.com.cn 微信:wlc5720 备注:开源中国