前言:
基于业务需求,需要实现多个系列的基于时间的流量趋势图折线图,实现联动的x轴的缩放和滚动浏览。之前用d3定制化了一版,但是基于后期需求扩展考虑,d3定制化开发成本较高,所以考虑基于Echarts实现。
1、基本效果截图
2、基于React自定义hook的代码实现:
SeriesChart.tsx组件封装:
import React, { useState, useEffect, useRef } from 'react';
import * as echarts from 'echarts';
import ReactEcharts from 'echarts-for-react';
import { dataTypeConfigList } from "../utils";
export default (props: any) => {
const { dataConfig, brushCallback, brushRange } = props;
const [option, setOption] = useState<any>(null);
const chartRef: any = useRef(null);
// 由于基于文档编写使用,此处用mock数据,实际业务需要定制化修改数据处理相关代码
function getRandomData() {
let base = +new Date(1988, 9, 3);
let oneDay = 24 * 3600 * 1000;
let data = [[base, Math.random() * 300]];
for (let i = 1; i < 2000; i++) {
let now = new Date((base += oneDay));
data.push([+now, Math.round((Math.random() - 0.5) * 20 + data[i - 1][1])]);
}
return data;
}
useEffect(() => {
type EChartsOption = echarts.EChartOption;
let option: EChartsOption;
let series = dataConfig.series.map((item: any) => {
let data = getRandomData();
return {
name: item.title,
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {},
// sampling: 'lttb', //开启大数量优化算法
data: data
}
})
option = {
color: ['#4cd698', '#4e5ad5', '#4eade9', '#f4914e', '#fcb75b', '#ffe180'],
tooltip: {
trigger: 'axis',
position: function (pt) {
return [pt[0], '10%'];
}
},
title: {
left: 'left',
text: dataConfig.title
},
grid: {
left: 50,
right: 40
},
legend: {
show: true,
icon: 'rect'
},
brush: {
xAxisIndex: 'all',
brushLink: 'all',
outOfBrush: {
colorAlpha: 0.1
}
},
toolbox: {
feature: {
brush: {
type: ['lineX', 'clear']
},
restore: {},
saveAsImage: {}
}
},
xAxis: {
type: 'time',
boundaryGap: false
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%']
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 10,
zoomLock: true
},
{
start: 0,
end: 10,
zoomLock: true
}
],
series: series
};
setOption(option);
setTimeout(() => {
let chartEl: any = chartRef?.current?.getEchartsInstance();
chartEl.group = 'flowChart';
echarts.connect('flowChart');
chartEl.on('brushEnd', (e: any) => {
// 笔刷框选x轴的范围数值
let range = e.areas[0].coordRange;
brushCallback(range);
})
})
}, []);
useEffect(() => {
let chartEl: any = chartRef?.current?.getEchartsInstance();
brushRange && chartEl && chartEl.dispatchAction({
type: 'brush',
areas: [
{
brushType: 'lineX',
coordRange: brushRange,
xAxisIndex: 0
}
]
});
}, [brushRange])
return <>
{
option && <ReactEcharts ref={chartRef}
option={option}
style={{ height: '240px', width: '100%' }}
/>
}
</>
}
utils数据配置文件代码如下:
export const dataTypeConfigList = [
{
title: '流量',
type: 'flow',
series: [
{ title: '总流量', key: 'totalByte' },
{ title: '进网流量', key: 'inboundByte' },
{ title: '出网流量', key: 'outboundByte' },
]
},
{
title: '数据包',
type: 'package',
series: [
{ title: '总数据包', key: 'totalPackage' },
{ title: '进网数据包', key: 'inboundPackage' },
{ title: '出网数据包', key: 'outboundPackage' },
]
}
];
实际使用的demo.tsx演示文件:
import React, { useState } from 'react';
import { Card } from 'antd';
import SeriesChart from './componets/SeriesChart';
import { dataTypeConfigList } from "./utils";
export default () => {
const [brushRange, setBrushRange] = useState<Array<any>>();
const brushCallback = (range: Array<any>) => {
setBrushRange(range);
}
return (
<div className='dashboard-page'>
<Card style={{ marginTop: 10 }}>
{
dataTypeConfigList.map((item: any) => {
return <SeriesChart dataConfig={item} key={item.type} brushCallback={brushCallback} brushRange={brushRange} />
})
}
</Card>
</div>
);
}
3、基本说明
基于基础代码部分,不用做过多说明了,这里只说主要的实现点和实现方案。图表联动时,需要基于Echarts图表实例的group
属性,然后调用echarts.connect('flowChart')
函数进行将多组图表关联,进行图表联动。这边的flowChart
是我自己命名的group
属性名。此处用setTimeout
的原因是,需要多组echarts图表实例进行初始化之后,再进行connect
才有用,所以此处这样处理。没有找到类似React中有类似Vue的$nextTick的API,如果大家有更好的处理方式,就在下方留言给予指正。
至于刷取框选部分,由于我需要考虑系统性能,在刷取结束时进行多图的统一框选,并且brush框选是不受group联动控制的,所以这样处理。
使用ReactEcharts
插件的原因是,该插件将Echarts基于React进行了二次封装,在基于窗口的大小尺寸改变时,图表能自动进行重绘。大家想直接使用Echarts也是可以的,就是相应的界面展示优化需要定制化处理而已。
4、写在最后
后续我会将之前d3定制化开发的版本进行分享,d3的优点就是方便直接改变样式进行主题切换处理;当然缺点也很明显就是开发维护成本高。