一、描述
由于上一篇文章已经介绍了处理方法,这篇文章主要展示处理数据的完整代码
1、处理数据的hooks
import http from '../../../../utils';
import rest from '../../../../common/rest.json';
import dayjs from 'dayjs';
import Utils from '../../../../tools'
import { useState } from 'react';
const useMultidimensionAlanalysisApi = (baseUrl) => {
const [tableData, setTableData] = useState([]); // 图表数据
const [loading, setLoading] = useState(false)
const [seriesData, setSeriesData] = useState([]);
const [Xdata, setXData] = useState([]);
const [lengedData, setLengedData] = useState([]);
const color = ['#FFC627', '#7EB338', '#009FF5', "#5E7DEC", "#BE271C"]
// 处理图表数据
const [yAxisArr, setYAxisArr] = useState([])
// 获取数据
const getData = (index, data, timeRange) => {
if (!data.length) return;
setLoading(true)
http.post(baseUrl + rest.energy.multidimension.pointData, {
pointNames: data.map((el) => el.text),
startTime: dayjs(timeRange[0]).format('YYYY-MM-DD 00:00:00'),
endTime: dayjs(timeRange[1]).format('YYYY-MM-DD 23:59:59')
}).then((res) => {
formatData(res.data.data);
setLoading(false)
}).catch((e) => {
console.log(e);
});
};
const formatData = (lineData) => {
if (lineData.length) {
lineData = lineData.sort(function (a, b) {
return b.unit.length - a.unit.length
})
const lengedArr = [];
let yAxisData = []
let timeData = [];
let unitData = []
lineData.forEach((el) => {
el.samples = el.samples.map(el => ({
...el,
value: el.value,
collectTime: Date.parse(el.collectTime)
})).sort(function (a, b) {
return a.collectTime - b.collectTime
})
timeData = el.samples.map(el => dayjs(el.collectTime).format("YYYY-MM-DD HH:mm"))
unitData.push(el?.unit)
});
setTableData(lineData)
unitData = [...new Set(unitData)]
setXData(timeData);
unitData.forEach((el, index) => {
yAxisData.push({
position: index === 0 ? "left" : "right",
// offset: formatdDistance(index),
type: 'value',
name: el,
nameTextStyle: {
color: "#A0A0A0",
fontSize: '.875rem',
padding: index === 0 ? [0, 35, 15, 0] : [0, 0, 15, 40]
},
alignTicks: true, // !!配置多坐标轴标签对齐
splitLine: {
lineStyle: {
color: '#707070',
},
},
axisLabel: {
fontSize: '.875rem',
color: '#A0A0A0',
},
})
})
const arr = lineData.map((el, index) => {
lengedArr.push(el.pointName);
const unitIndex = unitData.findIndex(item => item === el.unit)
return {
name: el.pointName,
type: 'line',
color: index < 5 ? color[index] : Utils.randomHexColor(),
data: el.samples.map((item) => item.value),
yAxisIndex: unitIndex,
symbol: 'circle',
symbolSize:8,
unit: el.unit,
// showAllSymbol:true
// connectNulls: true
};
});
setLengedData([...lengedArr]);
setYAxisArr([...yAxisData])
setSeriesData([...arr]);
} else {
setLengedData([]);
setSeriesData([]);
setTableData([])
}
};
return {
tableData,
seriesData,
lengedData,
Xdata,
yAxisArr,
loading,
getData,
setTableData,
setSeriesData,
};
};
export default useMultidimensionAlanalysisApi;
2、echarts组件
import React, { useEffect, useState, memo } from 'react';
import 'echarts/lib/component/markLine';
import 'echarts/lib/component/markPoint';
import Utils from '../../../../tools'
import ChartUtil from '../../../../common/chart/chart-util';
import { nowSize } from '../../../../common/commonUtil';
import { useECharts } from '../../../../common/chart/useECharts';
import { intervalScaleNiceTicks } from 'echarts/lib/scale/helper.js';
function getActualWidthOfChars(text, options = {}) {
const { size = 14, family = 'Honeywell Sans Web, Verdana, sans-serif' } = options;
let canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.font = `${size}px ${family}`;
const metrics = ctx.measureText(text);
const actual =
Math.abs(metrics.actualBoundingBoxLeft) +
Math.abs(metrics.actualBoundingBoxRight);
canvas = null;
return Math.max(metrics.width, actual);
}
function getMaxWidth(extend, option) {
let LMaxWidth = 0;
if (!(extend[0] === 0 && extend[1] === 0)) {
const lTick = intervalScaleNiceTicks(extend, 5);
const min =
lTick.niceTickExtent[0] < 0
? lTick.niceTickExtent[0] - lTick.interval
: lTick.niceTickExtent[0];
const max = lTick.niceTickExtent[1] + lTick.interval;
const lMin = Utils.formatNumber(min, 0);
const lMax = Utils.formatNumber(max, 0);
LMaxWidth = getActualWidthOfChars(
lMax.toString().length > lMin.toString().length ? lMax : lMin,
option
);
}
return LMaxWidth;
}
const LineChart = memo(
({ seriesData, Xdata, lengedData, style, theme, yAxisArr }) => {
const { setOptions: setLineChart, getInstance } = useECharts('LineChart', theme);
const fontFamily = 'Honeywell Sans Web, Verdana, sans-serif';
const fontSize = nowSize(14);
let otherWidth = 0
let lengedWidth = 0
let firstWidth = 0
let leftWidth = 0
const useLineChart = () => {
const option = {
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
type: 'slider', // slider表示有滑动块的,inside表示内置的
show: true, // 是否显示dataZoom,在完全自定义的时候需要用到
xAxisIndex: [0], // dataZoom控制的图标的是哪条x轴,因为会有多轴一图,可以控制多轴
// yAxisIndex: [0, 1], // dataZoom控制的图标的是哪条y轴,因为会有多轴一图,可以控制多轴
start: 0, // 和startValue不要弄混,这里是百分比
end: 100, // 和endValue不要弄混,这里是百分比
startValue: 0, // 滑块左端对应的x值
endValue: 500, // 滑块右端对应的x值
height: 10, // dataZoom整体高度
backgroundColor: '#404040',
filterMode: 'none', // 过滤模式,有filter, weakFilter, empty, none四个值,过滤会把整个数据段隐藏,而none则只是移动坐标轴
right: '4%',
// width: '90%',
left: '4.8%',
bottom: 0, // dataZoom相对图标的位置
animation: true, // 设置动画效果
throttle: 100, // 设置视图刷新的频率,ms
showDetail: true,
showDataShadow: false,
borderColor: '#0000', // dataZoom边框颜色
fillerColor: '#ffffff4c', // 滑块颜色
brushSelect: false, // 是否允许拖动滑块长度改变视图范围,不允许就是固定范围
handleIcon:
'M-9.35,34.56V42m0-40V9.5m-2,0h4a2,2,0,0,1,2,2v21a2,2,0,0,1-2,2h-4a2,2,0,0,1-2-2v-21A2,2,0,0,1-11.35,9.5Z',
},
],
tooltip: {
trigger: 'axis',
formatter: function (params) {
let str = '';
let title = '';
params?.forEach((item, index) => {
const unit = seriesData[seriesData.findIndex(el => el.name === item.seriesName)].unit
title = `<div style="color:#E0E0E0">${item.axisValue}</div>`;
str += `<div style="display:flex;align-items:center;background-color:#454545;">
<div style="width:.2437rem;height:.9375rem;margin-right:.6875rem;background:${item.color}"></div>
<div style="margin-left:.625rem;color:#A0A0A0;font">${item.seriesName}</div>
<div style="margin-left:.625rem;margin-right:.625rem;color:#FFFFFF">${item.value}</div>
<div style="color:#A0A0A0;margin-left:auto">${!unit ? "" : unit}</div>
</div>`;
});
return title + str;
},
extraCssText: `border-radius: .375rem;
border-color:#454545;
background-color:#454545;`,
},
xAxis: {
type: 'category',
data: Xdata,
name: Utils.translate('energy.multidimensionality.xUnit'),
axisPointer: {
type: 'shadow',
},
axisTick: {
alignWithLabel: true, // true:标签位于刻度线正下方;false:标签位于2个刻度线中间
},
nameTextStyle: {
// x轴name的样式调整
align: 'right',
color: '#A0A0A0',
fontSize: '1rem',
verticalAlign: 'top',
padding: [20, yAxisArr?.length === 1 ? -(leftWidth - 15) : -(otherWidth - 40), 0, 0],
},
axisLabel: {
margin: 20,
textStyle: {
color: '#A0A0A0',
fontSize: '1rem',
},
},
},
yAxis: yAxisArr,
grid: {
top: '18%',
left: leftWidth + 5,
right: otherWidth ? otherWidth < 260 ? otherWidth : 260 : leftWidth + 25,
bottom: '19%',
// containLabel: true,
},
legend: {
data: lengedData,
itemHeight: 8,
itemWidth: 14,
itemGap: 20,
orient: 'horizontal',
textStyle: {
color: '#A0A0A0',
fontSize: '.875rem',
},
right: lengedWidth,
y: 'top',
icon: 'path://M8.82929 2H12V4H8.82929C8.41746 5.16519 7.30622 6 6 6C4.69378 6 3.58254 5.16519 3.17071 4H0V2H3.17071C3.58254 0.834808 4.69378 0 6 0C7.30622 0 8.41746 0.834808 8.82929 2Z',
},
series: seriesData,
};
setLineChart(option)
}
useEffect(() => {
if (seriesData?.length) {
formatData(seriesData)
}
}, [seriesData]);
const formatData = (seriesData) => {
seriesData.forEach((el, index) => {
const LeftExtend = [0, 0];
const beforeLeftExtend = [0, 0]
const data = el.data.filter((item) => item !== '-').map((itme) => parseFloat(itme)) || [];
const beforeData = seriesData[index - 1]?.data.filter((item) => item !== '-').map((itme) => parseFloat(itme)) || [];
LeftExtend[1] = Math.max(...data) > LeftExtend[1] ? Math.max(...data) : LeftExtend[1];
beforeLeftExtend[1] = Math.max(...beforeData) > beforeLeftExtend[1] ? Math.max(...beforeData) : beforeLeftExtend[1];
const w = getActualWidthOfChars(Math.ceil(LeftExtend[1]).toString())
const w1 = getActualWidthOfChars(Math.ceil(beforeLeftExtend[1]).toString())
if (yAxisArr[index]) {
yAxisArr[index].nameTextStyle = {
color: "#A0A0A0",
fontSize: '.875rem',
padding: index === 0 ? [0, nowSize(w + 15), nowSize(15), 0] : [0, 0, nowSize(15), nowSize(w + 15)]
}
if (index !== 0) {
otherWidth += Math.ceil(w) + 25
} else firstWidth = Math.ceil(w) + 30
if (index === 0 || index === 1) {
yAxisArr[index].offset = 0
} else yAxisArr[index].offset = yAxisArr[index - 1].offset + Math.ceil(w1) + 25
}
})
if (yAxisArr.length === 2) otherWidth += 25
lengedData.forEach((el) => {
lengedWidth += Math.ceil(getActualWidthOfChars(el))
})
lengedWidth = getMaxWidth(lengedWidth, {
size: fontSize,
family: fontFamily,
}) - 8
leftWidth = getActualWidthOfChars(Xdata[0]) / 2
useLineChart()
}
return <div
id="chart-LineChart"
style={style}
></div>
}
)
export default LineChart;