前言:我们业务有种图表展示是后端返回N个图表,然后每个图表里面的线不一定,每个线都有各自的单位换算,所有需要多个Y轴,且如果几条线的单位相同,那就只出现一种单位轴线,多个Y轴需要推算每个Y轴的偏移量(offset),一旦legend点击某个线条置灰,那个Y轴就要消失,重新计算Y轴偏移,确保图表不拥挤,美观。

放个效果吧

基于此,我封装了一个方法。代码有点乱糟糟,仅作自己备忘。
新建EchartsUtils.js,如下

import React from 'react';
import * as echarts from 'echarts';
import { EleResize } from '@/utils/esresize';
import dayjs from 'dayjs';
import { clearDeep } from '@/utils/validate';
const color = ['rgba(79,128,220,0.9)','rgba(209,52,186,0.9)','rgba(245,200,118,0.9)','rgba(255,243,108,0.9)','rgba(149,196,101,0.9)','rgba(171,205,248,0.9)','rgba(10,141,255,0.9)','rgba(204,153,255,0.9)','rgba(212,108,34,0.9)','rgba(153,255,255,0.9)','rgba(255,153,204,0.9)','rgba(255,204,204,0.9)','rgba(153,204,204,0.9)','rgba(204,153,153,0.9)','rgba(153,255,153,0.9)','rgba(149,196,101,0.9)','rgba(215,129,19,0.9)','rgba(185,109,248,0.9)',
];
/*** 封装图表方法二  通用监控图表  结合后端* @author * charts   所有图表数据  [Array]如下 :[{"chartName": "",//图表名称"metricLines": [//指标线集合{"chartNodes": [//x,y轴{"metricValue": "", //值"timestamp": 0 //时间}],"metricName": "",//指标名,即线条"unit": ""//指标单位}]}]* chartById  图表所存放容器id标识* ***/
export const toShowGeneralGraphQueryEchartsOptionUtils = (charts, chartById) => {const bigNumberTransform = (value) => {const newValue = ['', '', ''];let fr = 1000;let num = 3;let text1 = '';let fm = 1;while (value / fr >= 1) {fr *= 10;num += 1;// console.log('数字', value / fr, 'num:', num)}if (num <= 4) {// 千newValue[0] = parseInt(value / 1000) + '';newValue[1] = '千';} else if (num <= 8) {// 万text1 = parseInt(num - 4) / 3 > 1 ? '千万' : '万';// tslint:disable-next-line:no-shadowed-variablefm = text1 === '万' ? 10000 : 10000000;if (value % fm === 0) {newValue[0] = parseInt(value / fm) + '';} else {newValue[0] = parseFloat(value / fm).toFixed(2) + '';}newValue[1] = text1;} else if (num <= 16) {// 亿text1 = (num - 8) / 3 > 1 ? '千亿' : '亿';text1 = (num - 8) / 4 > 1 ? '万亿' : text1;text1 = (num - 8) / 7 > 1 ? '千万亿' : text1;// tslint:disable-next-line:no-shadowed-variablefm = 1;if (text1 === '亿') {fm = 100000000;} else if (text1 === '千亿') {fm = 100000000000;} else if (text1 === '万亿') {fm = 1000000000000;} else if (text1 === '千万亿') {fm = 1000000000000000;}if (value % fm === 0) {newValue[0] = parseInt(value / fm) + '';} else {newValue[0] = parseFloat(value / fm).toFixed(2) + '';}newValue[1] = text1;}if (value < 1000) {newValue[0] = value + '';newValue[1] = '';}return newValue.join('');};const toChartValues = (data) => {let obj = {max: '-',min: '-',avg: '-',};if (typeof data === 'object' && data.length > 0 && data?.some((i) => i == 0 || Number(i))) {let arr = data.map((i) => i && Number(i)).filter((o) => Number.isFinite(o));obj.max = Math.max(...arr).toFixed(2);obj.min = Math.min(...arr).toFixed(2);let sum = 0;for (let i = 0; i < arr.length; i++) {sum += Number(arr[i]);obj.avg = (sum / arr.length).toFixed(2);}}return obj;};//单位换算方法,里面的分别换算就不赘述了const toShowSeriesValue = (val, unit) => {let value = val;if (value === '-') {return value;}if (Number(value) || Number(value) == 0) {value = Number(value);} else {return value;}switch (unit) {case '℃':return value.toFixed(2) + '℃';case '%':return value.toFixed(2) + '%';case 'ms':return value.toFixed(2) + 'ms';case 'kbps':return bandwidthDisplay(value);case 'bps':return bandwidthToSize(value);case 'Bps':return bandwidthToSize1(value);case 'bit':return throughputDisplay4(value);case 'Byte':return throughputDisplay(value);case 'KB':return throughputDisplay2(value);case 'MB':return throughputDisplay3(value);case 's':return formatSeconds(value);default:return value + unit;//return bigNumberTransform(value)}};const deWeight = (data) => {let arr = [...data];for (var i = 0; i < arr.length - 1; i++) {for (var j = i + 1; j < arr.length; j++) {if (arr[i].unit == arr[j].unit) {arr.splice(j, 1);//因为数组长度减小1,所以直接 j++ 会漏掉一个元素,所以要 j--j--;}}}return arr;};const handleIndex = (arr1, arr2) => {for (var i = 0; i < arr1.length; i++) {for (var j = 0; j < arr2.length; j++) {if (arr1[i].unit == arr2[j].unit) {arr1[i].yAxisIndex = j;}}}return arr1;};const handleIndexUnit = (seriesName, data) => {for (var i = 0; i < data.length; i++) {if (seriesName == data[i].name) {return data[i].unit;}}};if (charts.length > 0) {for (let i = 0; i < charts.length; i++) {//console.log("图表个数=== ",  charts[i]);//图表个数let totalSeries = [];let totalYAxis = [];for (let j = 0; j < charts[i].metricLines.length; j++) {//data的数量就是图表中线的数量,实现动态加载//console.log('--------------图表的线条',charts[i].metricLines[j])let max =toChartValues(charts[i]?.metricLines[j]?.chartNodes?.map((i) => i.metricValue))?.max ||'-';let min =toChartValues(charts[i].metricLines[j]?.chartNodes?.map((i) => i.metricValue))?.min ||'-';let avg =toChartValues(charts[i].metricLines[j]?.chartNodes?.map((i) => i.metricValue))?.avg ||'-';let mySeries = {unit: charts[i]?.metricLines[j]?.unit,name:charts[i].metricLines[j].metricName +' ' +' max: ' +toShowSeriesValue(max, charts[i]?.metricLines[j]?.unit) +' min: ' +toShowSeriesValue(min, charts[i]?.metricLines[j]?.unit) +' avg: ' +toShowSeriesValue(avg, charts[i]?.metricLines[j]?.unit),type: 'line',symbol: 'circle', //实心圆showSymbol: true, //小点点。每个数据的点是否显示smooth: true, //平滑symbolSize: [2, 2],lineStyle: {color: color[j % 14],width: 2,},animation: true,itemStyle: {color: color[j % 14],},yAxisIndex: j,data:charts[i]?.metricLines[j]?.chartNodes?.map((o) => {return [dayjs(o.timestamp).format('YYYY-MM-DD HH:mm:ss'), o.metricValue];}) || [],}; //series每条线的数据endtotalSeries.push(mySeries);let myAxis = {unit: charts[i]?.metricLines[j]?.unit,position: j % 2 == 0 ? 'left' : 'right',offset: j % 2 == 0 ? (j != 0 ? 30 * (j - 1) + 30 : 0) : 30 * (j - 1),show: true,nameTextStyle: {color: color[j % 14],fontWeight: 'normal',fontSize: 10,},axisLine: {show: false, //坐标轴是否显示lineStyle: {color: color[j % 14],},},axisLabel: {formatter: function (value, index) {return toShowSeriesValue(value, charts[i]?.metricLines[j]?.unit);},},axisTick: {show: false, //坐标轴刻度},bz:charts[i].metricLines[j].metricName +' ' +' max: ' +toShowSeriesValue(max, charts[i]?.metricLines[j]?.unit) +' min: ' +toShowSeriesValue(min, charts[i]?.metricLines[j]?.unit) +' avg: ' +toShowSeriesValue(avg, charts[i]?.metricLines[j]?.unit),};totalYAxis.push(myAxis);}// const headerStyle = document.getElementById(chartById+i);// if(headerStyle) {//     if((totalSeries.length)/2<3){//       headerStyle.style = `height:100%;padding-right:-70px`//     }else{//       headerStyle.style = `height:100%;padding-bottom:-${(totalSeries.length)/2*32}px`//     }// }let option = {title: {text: charts[i].chartName,textStyle: {fontSize: 14,align: 'left',color: 'rgba(42,25,91,1)', //title颜色灰色应该就可以},x: 'center',},grid: {//bottom:(totalSeries.length)/2<1?(totalSeries.length)*50:(totalSeries.length)/2*66,bottom:totalSeries.length / 2 < 1? totalSeries.length * 50: totalSeries.length < 4? (totalSeries.length / 2) * 66: 60,right: 40,left: 40,//right:(totalSeries.length)/2<1?'8%': `${(totalSeries.length)/2*8}%`,//left:(totalSeries.length)/2<1?'8%':(totalSeries.length)%2==0 ? `${(totalSeries.length)/2*8}%` :`${(totalSeries.length)/2*9}%`,containLabel: true,},// grid:{//     top:'10%',right:'8%', left:'12%',bottom:70// },dataZoom: [{type: 'inside',start: 0,end: 100,},],tooltip: {confine: true,trigger: 'axis',backgroundColor: '#fff',textStyle: {fontSize: 14,align: 'left',color: '#808080', //title颜色灰色应该就可以},borderWidth: 1,borderColor: '#ccc',borderRadius: 8, //边框圆角padding: [10, 10, 10, 10], // 内边距extraCssText: 'height:auto',formatter: function (data1) {//console.log('data1===========',data1);let detial = data1[0].axisValueLabel + '<br/>';if (data1.length > 0) {data1.map((item, index) => {let itemValue =item.value[1] == 0 || item.value[1]? toShowSeriesValue(item.value[1],totalSeries.find(array => array.name === item.seriesName)?.unit): '-';detial =detial + item.marker + item.seriesName.split(' ')[0] + ' ' + itemValue + '<br/>';});}return detial;},},legend: [{icon: 'circle',bottom: 0,type: 'scroll',itemGap: 8,itemWidth: 10,data: totalSeries?.map((i) => i.name)?.filter((o, index) => index % 2 == 0),},{icon: 'circle',bottom: 30,type: 'scroll',itemGap: 8,itemWidth: 10,data: totalSeries?.map((i) => i.name)?.filter((o, index) => index % 2 != 0),},],//这里legend,grid二次覆盖上面的是支持两种legend样式,不必纠结legend: {icon: 'circle',itemGap: 6,type: 'scroll',top: '78%',left: 'center',orient: 'vertical',textStyle: {fontSize: 10,},formatter(val) {return val;},data: totalSeries?.map((i) => i.name),},grid: {right: 30,left: 30,top: '16%',bottom: '30%',containLabel: true,},xAxis: [{type: 'category',nameTextStyle: {color: 'rgba(147,159,189,1)',fontSize: 12,},axisLine: {show: false,lineStyle: {color: 'rgba(147,159,189,1)',},},axisTick: {show: false,},},],yAxis: deWeight(totalYAxis),series: handleIndex(totalSeries, deWeight(totalYAxis)),};if (document.getElementById(chartById + i)) {let myChart = echarts.init(document.getElementById(chartById + i));myChart.clear();myChart.setOption(option, true);let echartsid = document.getElementById(chartById + i);let listener = function () {myChart.resize();};//EleResize是让图表随着容器大小变化自由伸缩的方法,下面会贴出来EleResize.on(echartsid, listener);myChart.on('legendselectchanged', function (params) {let select_value = Object.values(params.selected);let YAxis = totalYAxis.filter((item, index) => {return select_value[index];});totalYAxis = totalYAxis.map((o,index)=>{let j = YAxis.findIndex(array => array.bz === o.bz)<0?999:YAxis.findIndex(array => array.bz === o.bz);return {...o,position: j % 2 == 0 ? 'left' : 'right',offset: j % 2 == 0 ? (j != 0 ? 30 * (j - 1) + 30 : 0) : 30 * (j - 1),}});let option = {title: {text: charts[i].chartName,textStyle: {fontSize: 14,align: 'left',color: 'rgba(42,25,91,1)', //title颜色灰色应该就可以},x: 'center',},grid: {//bottom:(totalSeries.length)/2<1?(totalSeries.length)*50:(totalSeries.length)/2*66,bottom:totalSeries.length / 2 < 1? totalSeries.length * 50: totalSeries.length < 4? (totalSeries.length / 2) * 66: 60,right: 40,left: 40,//right:(totalSeries.length)/2<1?'8%': `${(totalSeries.length)/2*8}%`,//left:(totalSeries.length)/2<1?'8%':(totalSeries.length)%2==0 ? `${(totalSeries.length)/2*8}%` :`${(totalSeries.length)/2*9}%`,containLabel: true,},// grid:{//     top:'10%',right:'8%', left:'12%',bottom:70// },dataZoom: [{type: 'inside',start: 0,end: 100,},],tooltip: {confine: true,trigger: 'axis',backgroundColor: '#fff',textStyle: {fontSize: 14,align: 'left',color: '#808080', //title颜色灰色应该就可以},borderWidth: 1,borderColor: '#ccc',borderRadius: 8, //边框圆角padding: [10, 10, 10, 10], // 内边距extraCssText: 'height:auto',formatter: function (data1) {//console.log('data1===========',data1);let detial = data1[0].axisValueLabel + '<br/>';if (data1.length > 0) {data1.map((item, index) => {let itemValue =item.value[1] == 0 || item.value[1]? toShowSeriesValue(item.value[1],totalSeries.find(array => array.name === item.seriesName)?.unit): '-';detial =detial + item.marker + item.seriesName.split(' ')[0] + ' ' + itemValue + '<br/>';});}return detial;},},legend: [{icon: 'circle',bottom: 0,type: 'scroll',itemGap: 8,itemWidth: 10,data: totalSeries?.map((i) => i.name)?.filter((o, index) => index % 2 == 0),},{icon: 'circle',bottom: 30,type: 'scroll',itemGap: 8,itemWidth: 10,data: totalSeries?.map((i) => i.name)?.filter((o, index) => index % 2 != 0),},],legend: {icon: 'circle',itemGap: 6,type: 'scroll',top: '78%',left: 'center',orient: 'vertical',textStyle: {fontSize: 10,},formatter(val) {return val;},data: totalSeries?.map((i) => i.name),selected: Object.fromEntries(totalSeries?.map((i,index) => {let bool = select_value[index] ? true : false;console.log(bool)return [[i.name],bool]}))},grid: {right: 30,left: 30,top: '16%',bottom: '30%',containLabel: true,},xAxis: [{type: 'category',nameTextStyle: {color: 'rgba(147,159,189,1)',fontSize: 12,},axisLine: {show: false,lineStyle: {color: 'rgba(147,159,189,1)',},},axisTick: {show: false,},},],yAxis: deWeight(totalYAxis),series: handleIndex(totalSeries, deWeight(totalYAxis)),};myChart.clear();myChart.setOption(option, true);});}}}
};

esresize.js文件如下:

var EleResize = {_handleResize: function (e) {var ele = e.target || e.srcElement;var trigger = ele.__resizeTrigger__;if (trigger) {var handlers = trigger.__z_resizeListeners;if (handlers) {var size = handlers.length;for (var i = 0; i < size; i++) {var h = handlers[i];var handler = h.handler;var context = h.context;handler.apply(context, [e]);}}}},_removeHandler: function (ele, handler, context) {var handlers = ele.__z_resizeListeners;if (handlers) {var size = handlers.length;for (var i = 0; i < size; i++) {var h = handlers[i];if (h.handler === handler && h.context === context) {handlers.splice(i, 1);return;}}}},_createResizeTrigger: function (ele) {var obj = document.createElement('object');obj.setAttribute('style','display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -1;',);obj.onload = EleResize._handleObjectLoad;obj.type = 'text/html';ele.appendChild(obj);obj.data = 'about:blank';return obj;},_handleObjectLoad: function (evt) {this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;this.contentDocument.defaultView.addEventListener('resize', EleResize._handleResize);},
};
if (document.attachEvent) {// ie9-10EleResize.on = function (ele, handler, context) {var handlers = ele.__z_resizeListeners;if (!handlers) {handlers = [];ele.__z_resizeListeners = handlers;ele.__resizeTrigger__ = ele;ele.attachEvent('onresize', EleResize._handleResize);}handlers.push({handler: handler,context: context,});};EleResize.off = function (ele, handler, context) {var handlers = ele.__z_resizeListeners;if (handlers) {EleResize._removeHandler(ele, handler, context);if (handlers.length === 0) {ele.detachEvent('onresize', EleResize._handleResize);delete ele.__z_resizeListeners;}}};
} else {EleResize.on = function (ele, handler, context) {var handlers = ele.__z_resizeListeners;if (!handlers) {handlers = [];ele.__z_resizeListeners = handlers;if (getComputedStyle(ele, null).position === 'static') {ele.style.position = 'relative';}var obj = EleResize._createResizeTrigger(ele);ele.__resizeTrigger__ = obj;obj.__resizeElement__ = ele;}handlers.push({handler: handler,context: context,});};EleResize.off = function (ele, handler, context) {var handlers = ele.__z_resizeListeners;if (handlers) {EleResize._removeHandler(ele, handler, context);if (handlers.length === 0) {var trigger = ele.__resizeTrigger__;if (trigger) {trigger.contentDocument.defaultView.removeEventListener('resize',EleResize._handleResize,);ele.removeChild(trigger);delete ele.__resizeTrigger__;}delete ele.__z_resizeListeners;}}};
}
export { EleResize };

关于echarts的N个图表N条线N种单位的封装相关推荐

  1. Android 通过shape画线,1条线2种颜色,左边线条和背景色一致,右边线条为divider颜色

    Android 通过shape画线,1条线2种颜色,左边线条和背景色一致,右边线条为divider颜色 有时候ListView的Item分割线,会隔断,不是一条完整的横线,参考如下. 效果图: 如图中 ...

  2. echarts 在两点之间画一条线_凭什么?辛辛苦苦画了三个小时,却换来一句“撕了重画”...

    最近一位正在集训的同学找我吐槽. △学生聊天截图 每次听到这种事情我特么能气死,这些败类怎么还能够在各大画室之间游刃有余? 首先对于撕画这个问题,榜姐是不赞同的. 师者,传道授业解惑也! 棍棒底下出孝 ...

  3. echarts 在两点之间画一条线_树的手绘很难画?分步骤教你画,简单易学,收藏起来临摹学习...

    前景树--半树.角树画法 半树与角树,在建筑手绘中常处于前景位置,其表现需尽量写意,形体概括,对比强烈,进而更好地引导与突出中景. (1)半树 半树,顾名思义只需画出单棵树从树冠中下部到树根接地的位置 ...

  4. html 一条线两种颜色,HTML5/CSS3超酷进度条 不同进度多种颜色

    本文作者html5tricks,转载请注明出处 这是一款线条状的 下面我们来看看实现这款进度条的过程和源码,代码主要由HTML.CSS以及jQuery组成,实现过程也相对比较简单. HTML代码: 0 ...

  5. 如何利用echarts图表获取条状图点击名称和值

    如何利用echarts图表获取条状图点击名称和值 听语音 | 浏览:1505 | 更新:2017-06-13 10:20 | 标签:软件 1 2 3 4 5 6 7 分步阅读 echarts图表插件工 ...

  6. 数据可视化-echarts入门、常见图表案例、超详细配置解析及项目案例

    文章目录 数据可视化-echarts入门.常见图表案例及项目案例 一.简介 一.数据可视化简介 二.echarts简介 三.echarts特点 四.ZRender介绍 二.Echarts的基本使用 一 ...

  7. echarts折线图动态多条线

    echarts折线图配置项 由于工作中遇到的图表特别多,每次用过配置项总是想不起来,在这里记录一下,希望也可以帮到路过的你.话不多说我们上图: 左边的是设计稿,右边的是echarts的示例图,我们先找 ...

  8. 5分钟上手写ECharts的第一个图表

    方法一  :模块化单文件引入 1.新建一个echarts.html文件,为ECharts准备一个具备大小(宽高)的Dom. <!DOCTYPE html> <head>< ...

  9. Echarts数据可视化event图表事件的相关操作,开发全解+完美注释

    全栈工程师开发手册 (作者:栾鹏) Echarts数据可视化开发代码注释全解 Echarts数据可视化开发参数配置全解 6大公共组件详解(点击进入): title详解. tooltip详解.toolb ...

最新文章

  1. zabbix添加自定义监控项目-配置邮件告警-测试告警
  2. 2014年02月16日
  3. Js Call方法详解(js 的继承)
  4. 学习笔记(九)——JSON 和 AJAX
  5. linux 看硬盘运行时间长,Ubuntu 14.04查看硬盘使用时间
  6. 在Java中使用FileChannel和ByteBuffer对文件进行读写
  7. [css] 使用css如何设置背景虚化?
  8. .deploy 文件 php,关于php:Heroku deploy自动删除服务器文件?
  9. 1.3编程基础之算术表达式与顺序执行 01 A+B问题
  10. 10-Python入门学习-函数的对象与嵌套、名称空间与作用域、闭包函数
  11. iphone怎么重启_iPhone看完这个都要卡死机!这串神秘代码,是真的有毒
  12. Android 一个页面上下两个ListView的页面显示
  13. 蓝桥杯c语言基础试题答案,蓝桥杯试题C语言答案.doc
  14. SecureCRT8.1下载+注册机+破解教程
  15. win10熄屏时间不对_win10系统屏幕熄屏时间的设置方法
  16. 短信验证码 超时 java_短信验证码被刷怎么办?java 短信验证码防刷策略
  17. 第7课:郭盛华课程PHP超全局变量
  18. 网站域名https显示证书错误如何解决
  19. 计算机锁屏图片怎么设置方法,怎么设置电脑锁屏图片 电脑锁屏图片设置步骤...
  20. 第一篇自用博客:git的操作(防忘记用的hh)封面是我最爱的歌手ikura强推她的每一首歌,简直就是行走的唱片啊有木有!

热门文章

  1. 8.FindWindow(SSDT Shadow HOOK)
  2. 佰钧成java招聘_2021年佰钧成招聘-佰钧成招聘求职信息-拉勾招聘
  3. 本地客户端 dbeaver-连接HIVE库
  4. Numpy:np.tile()函数
  5. 任意阶数实数方阵的行列式的值的C语言实现详解
  6. 详解字符函数和字符串函数
  7. 企业数字化成功转型的关键,从这三方面出发
  8. RF工程师必须掌握的内容:从浅入深解说S参数
  9. 全志D1 哪吒开发板刷机记录
  10. mybatis plus一对多查询(经典案例)