监控领域中的Echarts 定制化封装之可联动ConnectCharts和可拖拽缩放GridCharts

监控领域中的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 group 的 id,或者图表实例的数组。

示例:

// 分别设置每个实例的 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 用到该技术的项目还是挺多。

特点:

  • 100% React - no jQuery
  • Compatible with server-rendered apps
  • Draggable widgets
  • Resizable widgets
  • Static widgets
  • Configurable packing: horizontal, vertical, or off
  • Bounds checking for dragging and resizing
  • Widgets may be added or removed without rebuilding grid
  • Layout can be serialized and restored
  • Responsive breakpoints
  • Separate layouts per responsive breakpoint
  • Grid Items placed using CSS Transforms
  • Performance: on / off, note paint (green) as % of time

 

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   备注:开源中国

转载于:https://my.oschina.net/u/3298482/blog/2249096

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值