Commit 365230d8 authored by 陈龙's avatar 陈龙

fix: 修复历史曲线频率、状态的图表显示异常

parent 4ea22fe6
This source diff could not be displayed because it is too large. You can view the blob instead.
import moment from 'moment'; import moment from 'moment';
import _, {isArray} from 'lodash'; import _, { isArray } from 'lodash';
import maxIcon from './assets/最大实心.svg'; import maxIcon from './assets/最大实心.svg';
import minIcon from './assets/最小实心.svg'; import minIcon from './assets/最小实心.svg';
import minIconDownArrow from './assets/最小实心箭头朝下.svg'; import minIconDownArrow from './assets/最小实心箭头朝下.svg';
import lineChart from '@wisdom-components/basicchart/es/LineChart'; import lineChart from '@wisdom-components/basicchart/es/LineChart';
import * as echarts from "echarts"; import * as echarts from 'echarts';
/** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */ /** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */
const AXIS_WIDTH = 40; const AXIS_WIDTH = 40;
const COLOR = { const COLOR = {
NORMAL: '#1685FF', NORMAL: '#1685FF',
UPER: '#fa8c16', UPER: '#fa8c16',
UPUPER: '#FF0000', UPUPER: '#FF0000',
// LOWER: '#13c2c2', // LOWER: '#13c2c2',
// LOWLOWER: '#2f54eb', // LOWLOWER: '#2f54eb',
LOWER: '#fa8c16', LOWER: '#fa8c16',
LOWLOWER: '#FF0000', LOWLOWER: '#FF0000',
AVG: '#00B8B1', AVG: '#00B8B1',
}; };
const isMobile = () => { const isMobile = () => {
const userAgent = navigator.userAgent.toLowerCase(); const userAgent = navigator.userAgent.toLowerCase();
if (/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(userAgent)) { if (/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(userAgent)) {
return true; return true;
} }
return false; return false;
}; };
const returnRem = (num, base = 375) => num * (base / 375); const returnRem = (num, base = 375) => num * (base / 375);
export const handlePx = (num, unit = '') => { export const handlePx = (num, unit = '') => {
const _isMobile = isMobile(); const _isMobile = isMobile();
const _base = document.body.clientWidth; const _base = document.body.clientWidth;
let _num = _isMobile ? `${returnRem(num, _base)}` : `${num}`; let _num = _isMobile ? `${returnRem(num, _base)}` : `${num}`;
return unit ? `${_num}${unit}` : Number(_num); return unit ? `${_num}${unit}` : Number(_num);
}; };
const PC_OPTION = { const PC_OPTION = {
markPoint: { markPoint: {
padding: [2, 12], padding: [2, 12],
lineHeight: 22, lineHeight: 22,
backgroundColor: backgroundColor:
window.globalConfig && window.globalConfig && window.globalConfig.variableTheme?.primaryColor window.globalConfig && window.globalConfig && window.globalConfig.variableTheme?.primaryColor
? window.globalConfig.variableTheme.primaryColor ? window.globalConfig.variableTheme.primaryColor
: '#0087F7', : '#0087F7',
borderWidth: 1, borderWidth: 1,
}, },
fontSize: 16, fontSize: 16,
fontColor: '#ffffff', fontColor: '#ffffff',
dataZoomHeight: 28, dataZoomHeight: 28,
}; };
const MOBILE_OPTION = { const MOBILE_OPTION = {
markPoint: { markPoint: {
padding: [2, 6], padding: [2, 6],
lineHeight: 18, lineHeight: 18,
backgroundColor: 'rgba(255,255,255,0.6)', backgroundColor: 'rgba(255,255,255,0.6)',
borderWidth: 0, borderWidth: 0,
}, },
fontSize: handlePx(12), fontSize: handlePx(12),
fontColor: '#0087F7', fontColor: '#0087F7',
dataZoomHeight: 20, dataZoomHeight: 20,
}; };
const currentOption = isMobile() ? MOBILE_OPTION : PC_OPTION; const currentOption = isMobile() ? MOBILE_OPTION : PC_OPTION;
/** /**
...@@ -68,13 +68,13 @@ const currentOption = isMobile() ? MOBILE_OPTION : PC_OPTION; ...@@ -68,13 +68,13 @@ const currentOption = isMobile() ? MOBILE_OPTION : PC_OPTION;
* @returns * @returns
*/ */
const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => { const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => {
const {equipmentName, sensorName, unit, dataModel, dateFrom, dateTo} = data; const { equipmentName, sensorName, unit, dataModel, dateFrom, dateTo } = data;
let name = nameWithSensor ? `${equipmentName}-${sensorName}` : equipmentName; let name = nameWithSensor ? `${equipmentName}-${sensorName}` : equipmentName;
if (contrast) { if (contrast) {
const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, ''); const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, '');
name = `${name}-${time}`; name = `${name}-${time}`;
} }
return name; return name;
}; };
/** /**
...@@ -86,14 +86,14 @@ const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => { ...@@ -86,14 +86,14 @@ const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => {
* @returns 图表系列数据, [[DateTime, value]] * @returns 图表系列数据, [[DateTime, value]]
*/ */
const dataAccessor = (data, contrast, contrastOption) => { const dataAccessor = (data, contrast, contrastOption) => {
const dataModel = data?.dataModel ?? []; const dataModel = data?.dataModel ?? [];
const formatStr = contrastOption === 'day' ? '2020-01-01 HH:mm:ss' : '2020-01-DD HH:mm:ss'; const formatStr = contrastOption === 'day' ? '2020-01-01 HH:mm:ss' : '2020-01-DD HH:mm:ss';
return dataModel return dataModel
.filter((item) => item.sensorName !== '是否在线') .filter((item) => item.sensorName !== '是否在线')
.map((item) => { .map((item) => {
const time = contrast ? moment(item.pt).format(formatStr) : item.pt; const time = contrast ? moment(item.pt).format(formatStr) : item.pt;
return [moment(time).valueOf(), item.pv]; return [moment(time).valueOf(), item.pv];
}); });
}; };
/** /**
...@@ -103,8 +103,8 @@ const dataAccessor = (data, contrast, contrastOption) => { ...@@ -103,8 +103,8 @@ const dataAccessor = (data, contrast, contrastOption) => {
* @returns Null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图. * @returns Null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图.
*/ */
const areaStyleFormatter = (data) => { const areaStyleFormatter = (data) => {
const {sensorName} = data; const { sensorName } = data;
return sensorName && sensorName.indexOf('流量') > -1 ? {} : null; return sensorName && sensorName.indexOf('流量') > -1 ? {} : null;
}; };
/** /**
...@@ -114,100 +114,100 @@ const areaStyleFormatter = (data) => { ...@@ -114,100 +114,100 @@ const areaStyleFormatter = (data) => {
* @returns * @returns
*/ */
const minMax = (data) => { const minMax = (data) => {
const {dataModel} = data; const { dataModel } = data;
let min = Number.MAX_SAFE_INTEGER; let min = Number.MAX_SAFE_INTEGER;
let max = Number.MIN_SAFE_INTEGER; let max = Number.MIN_SAFE_INTEGER;
dataModel.forEach((item) => { dataModel.forEach((item) => {
min = Math.min(min, item.pv ?? 0); min = Math.min(min, item.pv ?? 0);
max = Math.max(max, item.pv ?? 0); max = Math.max(max, item.pv ?? 0);
}); });
return [min, max]; return [min, max];
}; };
const markLineItem = (name, value, color) => { const markLineItem = (name, value, color) => {
return { return {
name: name, name: name,
yAxis: value, yAxis: value,
value: value, value: value,
lineStyle: { lineStyle: {
color: color || '#000', color: color || '#000',
}, },
label: { label: {
position: 'insideEndTop', position: 'insideEndTop',
color: color || '#000', color: color || '#000',
formatter: function () { formatter: function () {
return `${name}:${value}`; return `${name}:${value}`;
}, },
}, },
}; };
}; };
export const alarmMarkLine = (dataItem, index, dataSource, schemes) => { export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
// 只有一个数据曲线时显示markline // 只有一个数据曲线时显示markline
if (!dataItem || !schemes || dataSource.length !== 1) return {}; if (!dataItem || !schemes || dataSource.length !== 1) return {};
const {deviceType, stationCode, sensorName, decimalPoint} = dataItem; const { deviceType, stationCode, sensorName, decimalPoint } = dataItem;
const curSchemes = schemes.filter( const curSchemes = schemes.filter(
(item) => (item) =>
item.deviceCode === stationCode && item.deviceCode === stationCode &&
item.sensorName === sensorName && item.sensorName === sensorName &&
item.valueType === '直接取值', item.valueType === '直接取值',
); );
const data = []; const data = [];
curSchemes.forEach((scheme) => { curSchemes.forEach((scheme) => {
const {hLimit, hhLimit, lLimit, llLimit} = scheme; const { hLimit, hhLimit, lLimit, llLimit } = scheme;
lLimit !== null && lLimit !== void 0 && data.push(markLineItem('低限', lLimit, '#fa8c16')); lLimit !== null && lLimit !== void 0 && data.push(markLineItem('低限', lLimit, '#fa8c16'));
hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16')); hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16'));
llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000')); llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000'));
hhLimit !== null && hhLimit !== void 0 && data.push(markLineItem('高高限', hhLimit, '#FF0000')); hhLimit !== null && hhLimit !== void 0 && data.push(markLineItem('高高限', hhLimit, '#FF0000'));
}); });
data.push({ data.push({
name: '平均线', name: '平均线',
type: 'average', type: 'average',
lineStyle: { lineStyle: {
color: '#00b8b1', color: '#00b8b1',
type: 'solid', type: 'solid',
}, },
label: { label: {
position: 'insideEndTop', position: 'insideEndTop',
color: '#00b8b1', color: '#00b8b1',
formatter: function (param) { formatter: function (param) {
return `平均值:${param.value}`; return `平均值:${param.value}`;
}, },
}, },
}); });
return { return {
symbol: ['none', 'none'], symbol: ['none', 'none'],
data, data,
}; };
}; };
export const minMaxMarkPoint = (dataItem, index, dataSource) => { export const minMaxMarkPoint = (dataItem, index, dataSource) => {
const _isMobile = isMobile(); const _isMobile = isMobile();
// 只有一个数据曲线时显示markline // 只有一个数据曲线时显示markline
if (!dataItem || dataSource.length !== 1) return {}; if (!dataItem || dataSource.length !== 1) return {};
const data = [ const data = [
{ {
type: 'min', type: 'min',
value: null, value: null,
name: '最小: ', name: '最小: ',
symbol: `image://${minIcon}`, symbol: `image://${minIcon}`,
symbolOffset: [0, 18], symbolOffset: [0, 18],
}, },
{ {
type: 'max', type: 'max',
value: null, value: null,
name: '最大: ', name: '最大: ',
symbol: `image://${maxIcon}`, symbol: `image://${maxIcon}`,
symbolOffset: [0, -16], symbolOffset: [0, -16],
}, },
]; ];
return { return {
label: { label: {
show: false, show: false,
}, },
symbolSize: [49, 31], symbolSize: [49, 31],
data, data,
}; };
}; };
/** /**
...@@ -216,27 +216,27 @@ export const minMaxMarkPoint = (dataItem, index, dataSource) => { ...@@ -216,27 +216,27 @@ export const minMaxMarkPoint = (dataItem, index, dataSource) => {
* @param {any} axis * @param {any} axis
*/ */
export const decorateAxisGridLine = (axis, showGrid) => { export const decorateAxisGridLine = (axis, showGrid) => {
if (!axis) return; if (!axis) return;
axis.minorTick = { axis.minorTick = {
lineStyle: { lineStyle: {
color: '#e2e2e2', color: '#e2e2e2',
}, },
...(axis.minorTick || {}), ...(axis.minorTick || {}),
show: showGrid, show: showGrid,
splitNumber: 2, splitNumber: 2,
}; };
axis.minorSplitLine = { axis.minorSplitLine = {
lineStyle: { lineStyle: {
color: '#e2e2e2', color: '#e2e2e2',
type: 'dashed', type: 'dashed',
}, },
...(axis.minorSplitLine || {}), ...(axis.minorSplitLine || {}),
show: showGrid, show: showGrid,
}; };
axis.splitLine = { axis.splitLine = {
...(axis.splitLine || {}), ...(axis.splitLine || {}),
show: showGrid, show: showGrid,
}; };
}; };
/** /**
...@@ -245,691 +245,710 @@ export const decorateAxisGridLine = (axis, showGrid) => { ...@@ -245,691 +245,710 @@ export const decorateAxisGridLine = (axis, showGrid) => {
* @param {any} dataItem * @param {any} dataItem
*/ */
export const offlineArea = (dataItem) => { export const offlineArea = (dataItem) => {
if (!dataItem) return {}; if (!dataItem) return {};
const {dataModel} = dataItem; const { dataModel } = dataItem;
let datas = new Array(); let datas = new Array();
let offlineData = []; let offlineData = [];
let hasOffline = false; let hasOffline = false;
dataModel.forEach((item, index) => { dataModel.forEach((item, index) => {
if (!item.pv && !hasOffline) { if (!item.pv && !hasOffline) {
offlineData = [ offlineData = [
{ {
name: '离线', name: '离线',
xAxis: new Date(item.pt), xAxis: new Date(item.pt),
label: {show: !datas?.length}, label: { show: !datas?.length },
},
];
hasOffline = true;
} else if (item.pv && hasOffline) {
offlineData.push({
xAxis: new Date(item.pt),
});
datas.push(offlineData);
offlineData = [];
hasOffline = false;
}
});
return {
itemStyle: {
color: '#eee',
opacity: 0.6,
}, },
data: datas, ];
}; hasOffline = true;
} else if (item.pv && hasOffline) {
offlineData.push({
xAxis: new Date(item.pt),
});
datas.push(offlineData);
offlineData = [];
hasOffline = false;
}
});
return {
itemStyle: {
color: '#eee',
opacity: 0.6,
},
data: datas,
};
}; };
// tooltip 模板 // tooltip 模板
const headTemplate = (param, opt) => { const headTemplate = (param, opt) => {
if (!param) return ''; if (!param) return '';
const {name, axisValueLabel, axisType, axisValue} = param; const { name, axisValueLabel, axisType, axisValue } = param;
const timeFormat = const timeFormat =
opt && opt.contrast opt && opt.contrast
? opt.contrastOption === 'day' ? opt.contrastOption === 'day'
? 'HH:mm:ss' ? 'HH:mm:ss'
: 'DD日HH时' : 'DD日HH时'
: 'YYYY-MM-DD HH:mm:ss'; : 'YYYY-MM-DD HH:mm:ss';
const text = const text =
axisType === 'xAxis.time' ? moment(axisValue).format(timeFormat) : name || axisValueLabel; axisType === 'xAxis.time' ? moment(axisValue).format(timeFormat) : name || axisValueLabel;
return `<div style="border-bottom: 1px solid #F0F0F0; color: #808080; margin-bottom:${handlePx( return `<div style="border-bottom: 1px solid #F0F0F0; color: #808080; margin-bottom:${handlePx(
5, 5,
'px', 'px',
)}; padding-bottom: ${handlePx(5, 'px')};">${text}</div>`; )}; padding-bottom: ${handlePx(5, 'px')};">${text}</div>`;
}; };
const seriesTemplate = (param, unit) => { const seriesTemplate = (param, unit) => {
if (!param || param.seriesName === '自定义') return ''; if (!param || param.seriesName === '自定义') return '';
const {value, encode} = param; const { value, encode } = param;
// const val = value[encode.y[0]]; // const val = value[encode.y[0]];
const _unit = unit || ''; const _unit = unit || '';
const color = '#008CFF'; const color = '#008CFF';
if (!isArray(value)) if (!isArray(value))
return ` <div style="display: flex; align-items: center;"> return ` <div style="display: flex; align-items: center;">
<span style="${isMobile() <span style="${
? 'width: ' + isMobile()
handlePx(90, 'px') + ? 'width: ' +
';overflow:hidden;text-overflow:ellipsis;white-space:nowrap' handlePx(90, 'px') +
: '' ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
}">${param.seriesName}</span> : ''
}">${param.seriesName}</span>
<span style="display:inline-block;">:</span> <span style="display:inline-block;">:</span>
<span style="color:${color};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value?.toFixed(3) ?? '-' <span style="color:${color};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
}</span> value?.toFixed(3) ?? '-'
}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div>`; </div>`;
return param.componentSubType !== 'candlestick' return param.componentSubType !== 'candlestick'
? `<div style="display: flex; align-items: center;"> ? `<div style="display: flex; align-items: center;">
<span style="${isMobile() <span style="${
? 'width: ' + isMobile()
handlePx(90, 'px') + ? 'width: ' +
';overflow:hidden;text-overflow:ellipsis;white-space:nowrap' handlePx(90, 'px') +
: '' ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
}">${param.seriesName}</span><span style="display:inline-block;">:</span> : ''
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[1] ?? '-' }">${param.seriesName}</span><span style="display:inline-block;">:</span>
}</span> <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
value[1] ?? '-'
}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div>` </div>`
: ` : `
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span>首值</span><span style="display:inline-block;">:</span> <span>首值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[1] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
}</span> value[1] ?? '-'
}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span>尾值</span><span style="display:inline-block;">:</span> <span>尾值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[2] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
}</span> value[2] ?? '-'
}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span>周期最小值</span><span style="display:inline-block;">:</span> <span>周期最小值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[3] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
}</span> value[3] ?? '-'
}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span>周期最大值</span><span style="display:inline-block;">:</span> <span>周期最大值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[4] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
}</span> value[4] ?? '-'
}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
`; `;
}; };
const tooltipAccessor = (unit, contrastOption) => { const tooltipAccessor = (unit, contrastOption) => {
return { return {
formatter: function (params, ticket, callback) { formatter: function (params, ticket, callback) {
let tooltipHeader = ''; let tooltipHeader = '';
let tooltipContent = ''; let tooltipContent = '';
if (isArray(params)) { if (isArray(params)) {
tooltipHeader = headTemplate(params[0], contrastOption); tooltipHeader = headTemplate(params[0], contrastOption);
params.forEach((param) => { params.forEach((param) => {
tooltipContent += seriesTemplate(param, unit?.[param?.seriesIndex]); tooltipContent += seriesTemplate(param, unit?.[param?.seriesIndex]);
}); });
} else { } else {
tooltipHeader = headTemplate(params, contrastOption); tooltipHeader = headTemplate(params, contrastOption);
tooltipContent += seriesTemplate(params, unit?.[params?.seriesIndex]); tooltipContent += seriesTemplate(params, unit?.[params?.seriesIndex]);
} }
return ` return `
<div> <div>
${tooltipHeader} ${tooltipHeader}
<div>${tooltipContent}</div> <div>${tooltipContent}</div>
</div> </div>
`; `;
}, },
}; };
}; };
// 处理特殊业务:1. 频率;2. 是否在线(暂时不上) // 处理特殊业务:1. 频率;2. 是否在线(暂时不上)
const handleSpecial1 = (special, dataSource) => { const handleSpecial1 = (special, dataSource) => {
// 频率部分的业务 // 频率部分的业务
const _colorMap = { const _colorMap = {
变频: '#1685ff', 变频: '#1685ff',
工频: '#00d0c7', 工频: '#00d0c7',
运行: '#1685ff', 运行: '#1685ff',
故障: '#ff6b37', 故障: '#ff6b37',
停止: '#666666', 停止: '#666666',
}; };
let _special1 = special?.special1 ?? {}; let _special1 = special?.special1 ?? {};
let _valDesc = _special1?.valDesc ?? {}; let _valDesc = _special1?.valDesc ?? {};
let _data = dataSource.find((item) => item.sensorName === _special1.name); let _data = dataSource.find((item) => item.sensorName === _special1.name);
let _markAreaData = []; let _markAreaData = [];
let _pieces = let _pieces =
_data?.dataModel _data?.dataModel
?.reduce((final, cur, index) => { ?.reduce((final, cur, index) => {
let _pt = moment(cur.pt).valueOf(); let _pt = moment(cur.pt).valueOf();
let _length = final.length; let _length = final.length;
if (_colorMap[_valDesc[cur.pv]]) { if (_colorMap[_valDesc[cur.pv]]) {
if (_length === 0) { if (_length === 0) {
final.push({ final.push({
lte: _pt, lte: _pt,
gte: 0, gte: 0,
color: _colorMap[_valDesc[cur.pv]], color: _colorMap[_valDesc[cur.pv]],
value: cur.pv, value: cur.pv,
text: _valDesc[cur.pv], text: _valDesc[cur.pv],
}); });
} else { } else {
if (cur.pv === final[_length - 1].value) { if (cur.pv === final[_length - 1].value) {
final[_length - 1].lte = _pt; final[_length - 1].lte = _pt;
} else { } else {
final.push({ final.push({
lte: _pt, lte: _pt,
gte: _pt, gte: final[_length - 1].gte,
color: _colorMap[_valDesc[cur.pv]], color: _colorMap[_valDesc[cur.pv]],
value: cur.pv, value: cur.pv,
text: _valDesc[cur.pv], text: _valDesc[cur.pv],
}); });
} }
} }
} }
return final; return final;
}, []) }, [])
.map((item) => { .map((item) => {
_markAreaData.push([ _markAreaData.push([
{ {
xAxis: item.gte, xAxis: item.gte,
itemStyle: {
// color: item.color
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: item.color, // 0% 处的颜色
},
{
offset: 1,
color: item.color, // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
},
name: item.text,
label: {show: true},
},
{
xAxis: item.lte,
itemStyle: {
color: item.color,
},
},
]);
delete item.value;
return item;
}) ?? [];
let _final = {};
if (_markAreaData.length) {
_final.visualMap = {
type: 'piecewise',
show: false,
dimension: 0,
seriesIndex: 0,
pieces: _pieces,
};
}
if (_pieces.length) {
_final.markArea = {
silent: true,
itemStyle: { itemStyle: {
opacity: 0.1, // color: item.color
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: item.color, // 0% 处的颜色
},
{
offset: 1,
color: item.color, // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
}, },
data: _markAreaData, name: item.text,
}; label: { show: true },
} },
return _final; {
xAxis: item.lte,
itemStyle: {
color: item.color,
},
},
]);
delete item.value;
return item;
}) ?? [];
let _final = {};
if (_markAreaData.length) {
_final.visualMap = {
type: 'piecewise',
show: false,
dimension: 0,
seriesIndex: 0,
pieces: _pieces,
};
}
if (_pieces.length) {
_final.markArea = {
silent: true,
itemStyle: {
opacity: 0.1,
},
data: _markAreaData,
};
}
return _final;
}; };
// 生成x坐标 // 生成x坐标
const returnXAxis = ({ const returnXAxis = ({
dataSource, dataSource,
contrast, contrast,
contrastOption, contrastOption,
nameWithSensor, nameWithSensor,
showMarkLine, showMarkLine,
deviceAlarmSchemes, deviceAlarmSchemes,
showPoint, showPoint,
restOption, restOption,
smooth, smooth,
special, special,
yAxis yAxis,
}) => { }) => {
// 根据"指标名称"分类yAxis // 根据"指标名称"分类yAxis
const yAxisInterator = (() => { const yAxisInterator = (() => {
const map = new Map(); const map = new Map();
let current = -1; let current = -1;
const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name)); const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name));
return {get}; return { get };
})(); })();
let _offlineData = []; let _offlineData = [];
// 生成visualMap、markArea // 生成visualMap、markArea
let {visualMap, markArea} = handleSpecial1(special, dataSource); let { visualMap, markArea } = handleSpecial1(special, dataSource);
let _filterArr = ['是否在线']; let _filterArr = ['是否在线'];
if (special?.special1?.name) { if (special?.special1?.name) {
_filterArr.push(special.special1.name); _filterArr.push(special.special1.name);
} }
// 生成series // 生成series
let series = dataSource let series = dataSource
.filter((item) => { .filter((item) => {
if (item.sensorName === '是否在线') { if (item.sensorName === '是否在线') {
_offlineData.push(item); _offlineData.push(item);
} }
return !_filterArr.includes(item.sensorName); return !_filterArr.includes(item.sensorName);
}) })
.map((item, index) => { .map((item, index) => {
const {sensorName, unit} = item; const { sensorName, unit } = item;
const name = nameFormatter(item, contrast, contrastOption, nameWithSensor); const name = nameFormatter(item, contrast, contrastOption, nameWithSensor);
const data = dataAccessor(item, contrast, contrastOption); const data = dataAccessor(item, contrast, contrastOption);
const type = 'line'; const type = 'line';
const areaStyle = areaStyleFormatter(item); const areaStyle = areaStyleFormatter(item);
const _index = yAxis.findIndex(item => item.name === unit); const _index = yAxis.findIndex((item) => item.name === unit);
const yAxisIndex = _index > -1 ? _index : 0; const yAxisIndex = _index > -1 ? _index : 0;
const markLine = showMarkLine const markLine = showMarkLine
? alarmMarkLine(item, index, dataSource, deviceAlarmSchemes) ? alarmMarkLine(item, index, dataSource, deviceAlarmSchemes)
: {}; : {};
const markPoint = showPoint ? minMaxMarkPoint(item, index, dataSource) : {}; const markPoint = showPoint ? minMaxMarkPoint(item, index, dataSource) : {};
// let markArea = null; // let markArea = null;
// 需求变更:设备离线改用“是否在线”的数据,离线的状态标记的数据用该部分的数据。 2023年4月25日09:36:55 // 需求变更:设备离线改用“是否在线”的数据,离线的状态标记的数据用该部分的数据。 2023年4月25日09:36:55
// 暂时注释,离线逻辑需要再确认 2023-09-15 // 暂时注释,离线逻辑需要再确认 2023-09-15
/* let _offlineAreasData = _offlineData /* let _offlineAreasData = _offlineData
.find((offline) => offline.stationCode === item.stationCode); .find((offline) => offline.stationCode === item.stationCode);
let offlineAreas = offlineArea(_offlineAreasData); let offlineAreas = offlineArea(_offlineAreasData);
if (offlineAreas.data?.length) { if (offlineAreas.data?.length) {
restOption.markArea = null; restOption.markArea = null;
markArea = offlineAreas; markArea = offlineAreas;
}*/ }*/
// 需求新增:增加频率业务 // 需求新增:增加频率业务
return { return {
notMerge: true, notMerge: true,
name, name,
type, type,
data, data,
areaStyle, areaStyle,
yAxisIndex, yAxisIndex,
smooth, smooth,
unit, unit,
markLine, markLine,
markPoint, markPoint,
markArea, markArea,
}; };
}); });
// 由于series更新后,没有的数据曲线仍然停留在图表区上,导致图表可视区范围有问题 // 由于series更新后,没有的数据曲线仍然停留在图表区上,导致图表可视区范围有问题
const min = Math.min( const min = Math.min(
...series.map((item) => item.data?.[0]?.[0]).filter((item) => item !== undefined), ...series.map((item) => item.data?.[0]?.[0]).filter((item) => item !== undefined),
); );
const max = Math.max( const max = Math.max(
...series ...series
.map((item) => item.data?.[item.data.length - 1]?.[0]) .map((item) => item.data?.[item.data.length - 1]?.[0])
.filter((item) => item !== undefined), .filter((item) => item !== undefined),
); );
return { return {
xAxis: { xAxis: {
type: 'time', type: 'time',
min, min,
max, max,
axisLabel: { axisLabel: {
formatter: contrast formatter: contrast
? contrastOption === 'month' ? contrastOption === 'month'
? '{dd}日' ? '{dd}日'
: '{HH}:{mm}' : '{HH}:{mm}'
: { : {
year: '{yyyy}', year: '{yyyy}',
month: '{MMM}', month: '{MMM}',
day: '{d}日', day: '{d}日',
hour: '{HH}:{mm}', hour: '{HH}:{mm}',
minute: '{HH}:{mm}', minute: '{HH}:{mm}',
second: '{HH}:{mm}:{ss}', second: '{HH}:{mm}:{ss}',
none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}', none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}',
},
}, },
}, },
series, },
visualMap, series,
}; visualMap,
};
}; };
const handleDefault = (config, cusOption) => { const handleDefault = (config, cusOption) => {
const needUnit = _.get(config, 'needUnit', false); const needUnit = _.get(config, 'needUnit', false);
const curveCenter = _.get(config, 'curveCenter', false); const curveCenter = _.get(config, 'curveCenter', false);
const nameWithSensor = _.get(config, 'nameWithSensor', true); const nameWithSensor = _.get(config, 'nameWithSensor', true);
const showGridLine = _.get(config, 'showGridLine', true); const showGridLine = _.get(config, 'showGridLine', true);
const showMarkLine = _.get(config, 'showMarkLine', false); const showMarkLine = _.get(config, 'showMarkLine', false);
const showPoint = _.get(config, 'showPoint', false); const showPoint = _.get(config, 'showPoint', false);
const deviceAlarmSchemes = _.get(config, 'deviceAlarmSchemes', []); const deviceAlarmSchemes = _.get(config, 'deviceAlarmSchemes', []);
const chartType = _.get(config, 'chartType', null); const chartType = _.get(config, 'chartType', null);
const showBoxOption = _.get(config, 'showBoxOption', false); const showBoxOption = _.get(config, 'showBoxOption', false);
// 自定义属性 // 自定义属性
const restOption = _.pick(cusOption, ['title', 'legend']); const restOption = _.pick(cusOption, ['title', 'legend']);
const special = _.get(config, 'special', {}); const special = _.get(config, 'special', {});
return { return {
needUnit, needUnit,
curveCenter, curveCenter,
nameWithSensor, nameWithSensor,
showGridLine, showGridLine,
showMarkLine, showMarkLine,
showPoint, showPoint,
deviceAlarmSchemes, deviceAlarmSchemes,
chartType, chartType,
showBoxOption, showBoxOption,
restOption, restOption,
special, special,
}; };
}; };
const handleMaxValue = (value) => { const handleMaxValue = (value) => {
if (value <= 1) return value.toFixed(2); if (value <= 1) return value.toFixed(2);
if (value >= 100000) return `${(value / 1000).toFixed(2)}k`; if (value >= 100000) return `${(value / 1000).toFixed(2)}k`;
return value.toFixed(2); return value.toFixed(2);
} };
const reduceYAxis = (arr, dataSource) => { const reduceYAxis = (arr, dataSource) => {
let _offsetValue = []; let _offsetValue = [];
// 1. 合并相同单位的坐标轴 // 1. 合并相同单位的坐标轴
let _arr = arr.reduce((final, cur) => { let _arr = arr.reduce((final, cur) => {
let _key = cur.name === null ? 'null' : cur.name let _key = cur.name === null ? 'null' : cur.name;
if (!final[_key]) { if (!final[_key]) {
final[_key] = cur final[_key] = cur;
} }
return final;
}, {});
// 2. 合并相同单位的数据,找出最大值
let _maxValueArr = Object.values(
dataSource.reduce((final, cur) => {
let _key = cur.sensorName === null ? 'null' : cur.sensorName;
let _maxValue = cur.dataModel.reduce((final, cur) => {
// eslint-disable-next-line no-param-reassign
if (cur.pv > final) final = cur.pv;
return final; return final;
}, {}); }, 0);
// 2. 合并相同单位的数据,找出最大值 if (final[_key] === undefined) {
let _maxValueArr = Object.values(dataSource.reduce((final, cur) => { final[_key] = _maxValue;
let _key = cur.sensorName === null ? 'null' : cur.sensorName; } else {
let _maxValue = cur.dataModel.reduce((final, cur) => { final[_key] = Math.max([final[_key], _maxValue]);
// eslint-disable-next-line no-param-reassign }
if (cur.pv > final) final = cur.pv; return final;
return final }, {}),
}, 0); );
if (final[_key] === undefined) { // 3. 合并,生成Y轴配置
final[_key] = _maxValue return Object.values(_arr).map((item, index) => {
} else { let _key = item.name === null ? 'null' : item.name;
final[_key] = Math.max([final[_key], _maxValue]); let _lastAxisNumber = _maxValueArr[index - 2];
} let _baseOffset = _offsetValue[index - 2] ?? 0;
return final let _finalOffset =
}, {})); (_lastAxisNumber !== undefined // 没有相邻的轴
// 3. 合并,生成Y轴配置 ? (_lastAxisNumber === 0 ? 20 : _lastAxisNumber.toFixed(2).replaceAll('.', '').length) * 12
return Object.values(_arr).map((item, index) => { : 0) + _baseOffset;
let _key = item.name === null ? 'null' : item.name; _offsetValue.push(_finalOffset);
let _lastAxisNumber = _maxValueArr[index - 2]; return {
let _baseOffset = _offsetValue[index - 2] ?? 0; ...item,
let _finalOffset = ( offset: _finalOffset,
_lastAxisNumber !== undefined ? // 没有相邻的轴 position: index % 2 === 0 ? 'left' : 'right',
(_lastAxisNumber === 0 ? 20 : _lastAxisNumber.toFixed(2).replaceAll('.', '').length) * 12 nameTextStyle: {
: 0 align: index % 2 === 0 ? 'right' : 'left',
) + _baseOffset; },
_offsetValue.push(_finalOffset); };
return ({ });
...item,
offset: _finalOffset,
position: index % 2 === 0 ? 'left' : 'right',
nameTextStyle: {
align: index % 2 === 0 ? 'right' : 'left',
},
})
});
}; };
/** /**
* 1. 生成常规的yAxis配置; 2. 处理sensorType为状态值的指标,生成yAxis配置
* *
* 1. 生成常规的yAxis配置; * @param {array} dataSource 数据源
* 2. 处理sensorType为状态值的指标,生成yAxis配置 * @param {boolean} needUnit 是否显示单位。
* * @param {boolean} curveCenter 曲线是否居中。
* @param {array} dataSource 数据源 * @param {boolean} showGridLine 是否显示网格线。
* @param {boolean} needUnit 是否显示单位。 * @returns {object} 返回左右轴的margin、yAxis的配置。
* @param {boolean} curveCenter 曲线是否居中。 */
* @param {boolean} showGridLine 是否显示网格线。 const handleYAxis = ({ dataSource, needUnit, curveCenter, showGridLine }) => {
* @return {object} 返回左右轴的margin、yAxis的配置。 const yAxisMap = new Map();
* */ // 1. 找出最大值; 2. 计算出y轴最大宽度动态计算偏移距离;
const handleYAxis = ({dataSource, needUnit, curveCenter, showGridLine}) => { dataSource.forEach((item, index) => {
const yAxisMap = new Map(); const { sensorName, unit } = item;
// 1. 找出最大值; 2. 计算出y轴最大宽度动态计算偏移距离; const key = sensorName;
dataSource.forEach((item, index) => { if (!yAxisMap.has(key)) {
const {sensorName, unit} = item; const axis = {
const key = sensorName; type: 'value',
if (!yAxisMap.has(key)) { name: needUnit ? unit : null,
const axis = { axisLabel: {
type: 'value', formatter: (value) => {
name: needUnit ? unit : null, return handleMaxValue(value);
axisLabel: { },
formatter: (value) => { },
return handleMaxValue(value); axisLine: {
} show: true,
}, },
axisLine: { minorTick: {
show: true, lineStyle: {
}, color: '#e2e2e2',
minorTick: { },
lineStyle: { },
color: '#e2e2e2', minorSplitLine: {
}, lineStyle: {
}, color: '#e2e2e2',
minorSplitLine: { type: 'dashed',
lineStyle: { },
color: '#e2e2e2', },
type: 'dashed', };
}, yAxisMap.set(key, axis);
}, }
}; // 曲线居中
yAxisMap.set(key, axis); if (curveCenter && item.dataModel && item.dataModel.length > 0) {
} const [min, max] = minMax(item);
// 曲线居中 const axis = yAxisMap.get(key);
if (curveCenter && item.dataModel && item.dataModel.length > 0) { axis.min = axis.min === void 0 ? min : Math.min(min, axis.min);
const [min, max] = minMax(item); axis.max = axis.max === void 0 ? max : Math.max(max, axis.max);
const axis = yAxisMap.get(key); }
axis.min = axis.min === void 0 ? min : Math.min(min, axis.min); // 网格显示
axis.max = axis.max === void 0 ? max : Math.max(max, axis.max); const axis = yAxisMap.get(key);
} decorateAxisGridLine(axis, showGridLine);
// 网格显示 });
const axis = yAxisMap.get(key); const yAxis =
decorateAxisGridLine(axis, showGridLine); yAxisMap.size > 0 ? reduceYAxis([...yAxisMap.values()], dataSource) : { type: 'value' };
}); const leftNum = Math.ceil(yAxisMap.size / 2);
const yAxis = yAxisMap.size > 0 ? reduceYAxis([...yAxisMap.values()], dataSource) : {type: 'value'}; const rightNum = Math.floor(yAxisMap.size / 2);
const leftNum = Math.ceil(yAxisMap.size / 2); return { leftNum, rightNum, yAxis };
const rightNum = Math.floor(yAxisMap.size / 2);
return {leftNum, rightNum, yAxis};
}; };
/** /**
* 1. 最后的配置处理、合并 * 1. 最后的配置处理、合并
* dataZoom 缩放 * dataZoom 缩放
* xAxis.minInterval X轴的最小间隔 * xAxis.minInterval X轴的最小间隔
* legend legend配置 * legend legend配置
* @param {object} restOption 额外配置 *
* @param {object} xAxis x轴的配置 * @param {object} restOption 额外配置
* @param {array} legendData legend数组 * @param {object} xAxis X轴的配置
* @param {string} chartType 线型 lineChart|boxChart * @param {array} legendData Legend数组
* @param {boolean} contrast 是否为同期对比 * @param {string} chartType 线型 lineChart|boxChart
* @param {string} contrastOption 同期对比周期配置, day|month * @param {boolean} contrast 是否为同期对比
* @param {object} config 其他的配置 * @param {string} contrastOption 同期对比周期配置, day|month
* */ * @param {object} config 其他的配置
const assignOptions = (restOption, xAxis, legendData, chartType, contrast, contrastOption, config) => { */
restOption.dataZoom = [ const assignOptions = (
{ restOption,
show: true, xAxis,
bottom: 20, legendData,
start: 0, chartType,
end: 100, contrast,
height: config.isMultiple ? 20 : 28, contrastOption,
type: 'inside', config,
zoomOnMouseWheel: true, ) => {
filterMode: chartType === 'lineChart' ? 'none' : 'weakFilter', restOption.dataZoom = [
}, {
{ show: true,
show: true, bottom: 20,
bottom: 20, start: 0,
start: 0, end: 100,
end: 100, height: config.isMultiple ? 20 : 28,
height: config.isMultiple ? 20 : 28, type: 'inside',
type: 'slider', zoomOnMouseWheel: true,
zoomOnMouseWheel: true, filterMode: chartType === 'lineChart' ? 'none' : 'weakFilter',
labelFormatter: function (e) { },
let _formatterStr = 'YYYY-MM-DD HH:mm:ss'; {
if (contrast) { show: true,
if (contrastOption === 'day') _formatterStr = 'HH:mm'; bottom: 20,
if (contrastOption === 'month') _formatterStr = 'MM月DD日 HH时'; start: 0,
} end: 100,
return moment(e).format(_formatterStr); height: config.isMultiple ? 20 : 28,
}, type: 'slider',
}, zoomOnMouseWheel: true,
]; labelFormatter: function (e) {
xAxis.minInterval = 3600 * (1 * 1000); let _formatterStr = 'YYYY-MM-DD HH:mm:ss';
if (legendData) { if (contrast) {
restOption.legend = { if (contrastOption === 'day') _formatterStr = 'HH:mm';
...{ if (contrastOption === 'month') _formatterStr = 'MM月DD日 HH时';
show: true, }
right:10, return moment(e).format(_formatterStr);
top: 30, },
icon: 'rect', },
itemWidth: 14, ];
itemHeight: 8, xAxis.minInterval = 3600 * (1 * 1000);
itemGap: 20, if (legendData) {
}, ...restOption.legend, ...{data: legendData} restOption.legend = {
}; ...{
} show: true,
right: 10,
top: 30,
icon: 'rect',
itemWidth: 14,
itemHeight: 8,
itemGap: 20,
},
...restOption.legend,
...{ data: legendData },
};
}
}; };
const returnMaxOrMinNumber = (dataSource, type) => { const returnMaxOrMinNumber = (dataSource, type) => {
let _obj = null; let _obj = null;
if (type === 'period' && dataSource?.[0]?.dataModel?.length) { if (type === 'period' && dataSource?.[0]?.dataModel?.length) {
let _length = dataSource?.[0]?.dataModel?.length; let _length = dataSource?.[0]?.dataModel?.length;
let _first = dataSource?.[0]?.dataModel[0]?.pt; let _first = dataSource?.[0]?.dataModel[0]?.pt;
let _last = dataSource?.[0]?.dataModel[_length - 1]?.pt; let _last = dataSource?.[0]?.dataModel[_length - 1]?.pt;
return ['展示时段: ', _first, _last, type]; return ['展示时段: ', _first, _last, type];
} }
dataSource?.[0]?.dataModel dataSource?.[0]?.dataModel
.filter((item) => item.pv !== null) .filter((item) => item.pv !== null)
.forEach((item) => { .forEach((item) => {
if (!_obj) { if (!_obj) {
_obj = item; _obj = item;
} else { } else {
if (type === 'min') { if (type === 'min') {
if (item.pv < _obj.pv) { if (item.pv < _obj.pv) {
_obj = item; _obj = item;
} }
} }
if (type === 'max') { if (type === 'max') {
if (item.pv > _obj.pv) { if (item.pv > _obj.pv) {
_obj = item; _obj = item;
} }
} }
} }
}); });
let _value = []; let _value = [];
if (_obj?.pt) { if (_obj?.pt) {
_value = [moment(_obj.pt).valueOf(), _obj.pv]; _value = [moment(_obj.pt).valueOf(), _obj.pv];
let _img = type === 'max' ? maxIcon : minIconDownArrow; let _img = type === 'max' ? maxIcon : minIconDownArrow;
_value.push(_img); _value.push(_img);
_value.push(type); _value.push(type);
// 把最大值最小值都push进去,方便计算 // 把最大值最小值都push进去,方便计算
} }
return _value; return _value;
}; };
const handleGrid = (dataSource, needUnit, leftNum, rightNum, chartType) => { const handleGrid = (dataSource, needUnit, leftNum, rightNum, chartType) => {
// 如果是单曲线,_grid的top需要一行的高度,用来放置最值最小值 // 如果是单曲线,_grid的top需要一行的高度,用来放置最值最小值
let _base = 60; let _base = 60;
let _topForUnit = needUnit ? 20 : 0; let _topForUnit = needUnit ? 20 : 0;
return { return {
top: _base + _topForUnit, top: _base + _topForUnit,
left: 30, left: 30,
right: 10, right: 10,
bottom: 60, bottom: 60,
containLabel: true, containLabel: true,
}; };
}; };
const renderItem = (params, api) => { const renderItem = (params, api) => {
let _base = params.dataIndex; let _base = params.dataIndex;
let _baseChartWidth = 10; let _baseChartWidth = 10;
let _numberStringWidth = let _numberStringWidth =
_base === 1 && api.value(3) === 'max' _base === 1 && api.value(3) === 'max'
? String(api.value(4) || 0).length * _baseChartWidth ? String(api.value(4) || 0).length * _baseChartWidth
: String(api.value(1)).length * _baseChartWidth; : String(api.value(1)).length * _baseChartWidth;
let _left = 30; let _left = 30;
let _baseWidth = 190 + _numberStringWidth; let _baseWidth = 190 + _numberStringWidth;
let _imgWidth = 45; let _imgWidth = 45;
let _dateWidth = 128; let _dateWidth = 128;
let _imageX = _left + _base * _baseWidth; let _imageX = _left + _base * _baseWidth;
let _timeX = _left + _base * _baseWidth + _imgWidth; let _timeX = _left + _base * _baseWidth + _imgWidth;
let _valueX = _left + _base * _baseWidth + _imgWidth + _dateWidth; let _valueX = _left + _base * _baseWidth + _imgWidth + _dateWidth;
let _color = api.value(3) === 'min' ? '#05C2BC' : '#1685FF'; let _color = api.value(3) === 'min' ? '#05C2BC' : '#1685FF';
let topValue = 25; let topValue = 25;
let _trimmer = -2; let _trimmer = -2;
return { return {
type: 'group', type: 'group',
children: [ children: [
{ {
type: 'image', type: 'image',
style: { style: {
image: api.value(2), image: api.value(2),
textVerticalAlign: 'middle', textVerticalAlign: 'middle',
y: -6, y: -6,
}, },
position: [_imageX, topValue], position: [_imageX, topValue],
}, },
{ {
type: 'text', type: 'text',
style: { style: {
text: moment(api.value(0)).format('YYYY-MM-DD HH:mm:ss') + ': ', text: moment(api.value(0)).format('YYYY-MM-DD HH:mm:ss') + ': ',
textVerticalAlign: 'top', textVerticalAlign: 'top',
}, },
position: [_timeX, topValue + _trimmer], position: [_timeX, topValue + _trimmer],
}, },
{ {
type: 'text', type: 'text',
style: { style: {
text: api.value(1), text: api.value(1),
textVerticalAlign: 'middle', textVerticalAlign: 'middle',
fill: _color, fill: _color,
font: 'bolder 16px cursive', font: 'bolder 16px cursive',
lineWidth: 10, lineWidth: 10,
y: 3, y: 3,
}, },
position: [_valueX, topValue + _trimmer], position: [_valueX, topValue + _trimmer],
}, },
], ],
}; };
}; };
const returnCustomSeries = (dataSource) => { const returnCustomSeries = (dataSource) => {
let _maxNumber = returnMaxOrMinNumber(dataSource, 'max'); let _maxNumber = returnMaxOrMinNumber(dataSource, 'max');
let _minNumber = returnMaxOrMinNumber(dataSource, 'min'); let _minNumber = returnMaxOrMinNumber(dataSource, 'min');
// let _period = returnMaxOrMinNumber(dataSource, 'period'); // let _period = returnMaxOrMinNumber(dataSource, 'period');
// 需要将最大值最小分别传入,后续计算图例位置需要,先min后max // 需要将最大值最小分别传入,后续计算图例位置需要,先min后max
let _max = _maxNumber[1]; let _max = _maxNumber[1];
let _min = _minNumber[1]; let _min = _minNumber[1];
[_maxNumber, _minNumber].forEach((item) => { [_maxNumber, _minNumber].forEach((item) => {
item.push(_min); item.push(_min);
item.push(_max); item.push(_max);
}); });
return { return {
name: '自定义', name: '自定义',
type: 'custom', type: 'custom',
renderItem: renderItem, renderItem: renderItem,
data: [_minNumber, _maxNumber], data: [_minNumber, _maxNumber],
}; };
}; };
const renderStatusItem = (params, api) => { const renderStatusItem = (params, api) => {
var categoryIndex = api.value(0); var categoryIndex = api.value(0);
var start = api.coord([api.value(1), categoryIndex]); var start = api.coord([api.value(1), categoryIndex]);
var end = api.coord([api.value(2), categoryIndex]); var end = api.coord([api.value(2), categoryIndex]);
var height = api.size([0, 1])[1] * 0.4; var height = api.size([0, 1])[1] * 0.4;
var rectShape = echarts.graphic.clipRectByRect( var rectShape = echarts.graphic.clipRectByRect(
{ {
x: start[0], x: start[0],
y: start[1] - height / 2, y: start[1] - height / 2,
width: end[0] - start[0], width: end[0] - start[0],
height: height height: height,
}, },
{ {
x: params.coordSys.x, x: params.coordSys.x,
y: params.coordSys.y, y: params.coordSys.y,
width: params.coordSys.width, width: params.coordSys.width,
height: params.coordSys.height height: params.coordSys.height,
} },
); );
return ( return (
rectShape && { rectShape && {
type: 'rect', type: 'rect',
transition: ['shape'], transition: ['shape'],
shape: rectShape, shape: rectShape,
style: api.style() style: api.style(),
} }
); );
} };
/** /**
* 图表配置项生成 * 图表配置项生成
...@@ -943,440 +962,455 @@ const renderStatusItem = (params, api) => { ...@@ -943,440 +962,455 @@ const renderStatusItem = (params, api) => {
*/ */
const optionGenerator = ( const optionGenerator = (
dataSource,
cusOption,
contrast,
contrastOption,
smooth,
config,
lineDataType = '',
) => {
// 1. 处理配置,配置分配默认值;
const {
needUnit,
curveCenter,
nameWithSensor,
showGridLine,
showMarkLine,
showPoint,
deviceAlarmSchemes,
chartType,
showBoxOption,
restOption,
special,
} = handleDefault(config, cusOption);
const { leftNum, rightNum, yAxis } = handleYAxis({
dataSource,
needUnit,
curveCenter,
showGridLine,
});
let { xAxis, series, visualMap } = returnXAxis({
dataSource, dataSource,
cusOption,
contrast, contrast,
contrastOption, contrastOption,
nameWithSensor,
showMarkLine,
deviceAlarmSchemes,
showPoint,
smooth, smooth,
config, restOption,
lineDataType = '', special,
) => { yAxis,
// 1. 处理配置,配置分配默认值; });
const { // 3. 判断是否开启网格;
needUnit, const grid = handleGrid(dataSource, needUnit, leftNum, rightNum, chartType);
curveCenter, decorateAxisGridLine(xAxis, showGridLine);
nameWithSensor, const tooltipTimeFormat = !contrast
showGridLine, ? 'YYYY-MM-DD HH:mm:ss'
showMarkLine, : contrastOption === 'day'
showPoint, ? 'HH:mm'
deviceAlarmSchemes, : 'DD HH:mm';
chartType, let tooltip = {};
showBoxOption, // 增加箱线图的逻辑,单曲线才存在该逻辑
restOption, if (chartType && showBoxOption && !special?.special1?.name) {
special, if (chartType === 'boxChart' && lineDataType === '特征曲线') {
} = handleDefault(config, cusOption); const otherData =
const {leftNum, rightNum, yAxis} = handleYAxis({ dataSource?.[0]?.dataModel.map((item) => {
dataSource, const { firstPV, lastPV, maxPV, minPV, pt } = item;
needUnit, return [moment(pt).valueOf(), firstPV, lastPV, minPV, maxPV];
curveCenter, }) || []; //当存在othersData的时候,只是单曲线
showGridLine, xAxis = { type: 'time' };
}); decorateAxisGridLine(xAxis, showGridLine);
let {xAxis, series, visualMap} = returnXAxis({ let unit = [];
dataSource, series = series.map((item) => {
contrast, if (item.unit) unit.push(item.unit);
contrastOption, item.areaStyle = null;
nameWithSensor, return { ...item, showSymbol: false };
showMarkLine, });
deviceAlarmSchemes, // 箱线图去除曲线 2023年10月17日
showPoint, series = [
smooth, {
restOption, type: 'candlestick',
special, name: '箱线图',
yAxis symbol: 'none',
}); data: otherData,
// 3. 判断是否开启网格; itemStyle: {
const grid = handleGrid(dataSource, needUnit, leftNum, rightNum, chartType); color: '#FFA200',
decorateAxisGridLine(xAxis, showGridLine); color0: '#44CD00',
const tooltipTimeFormat = !contrast borderColor: '#FFA200',
? 'YYYY-MM-DD HH:mm:ss' borderColor0: '#44CD00',
: contrastOption === 'day' },
? 'HH:mm' },
: 'DD HH:mm'; ];
let tooltip = {}; tooltip = tooltipAccessor(unit);
// 增加箱线图的逻辑,单曲线才存在该逻辑 }
if (chartType && showBoxOption && !special?.special1?.name) { if (chartType === 'lineChart' || lineDataType === '原始曲线') {
if (chartType === 'boxChart' && lineDataType === '特征曲线') { let _maxData = [];
const otherData = let _minData = [];
dataSource?.[0]?.dataModel.map((item) => { let _currentYear = moment().format('YYYY');
const {firstPV, lastPV, maxPV, minPV, pt} = item; const formatStr =
return [moment(pt).valueOf(), firstPV, lastPV, minPV, maxPV]; contrastOption === 'day'
}) || []; //当存在othersData的时候,只是单曲线 ? `${_currentYear}-01-01 HH:mm:00`
xAxis = {type: 'time'}; : `${_currentYear}-01-DD HH:mm:00`; // 用来做同期对比,把日期拉到同一区间
decorateAxisGridLine(xAxis, showGridLine); let _maxValues = [];
let unit = []; /** 生成泳道图,分两种情况 1. 当最大值最小值都是正数时; 2. 当最大值小于零时(此时,最小值一定小于零); */
series = series.map((item) => { dataSource?.[0]?.dataModel.forEach((item) => {
if (item.unit) unit.push(item.unit); const { firstPV, lastPV, maxPV, minPV, pt } = item;
item.areaStyle = null; _maxValues.push(maxPV);
return {...item, showSymbol: false}; let time = contrast ? moment(pt).format(formatStr) : pt;
}); _maxData.push([
// 箱线图去除曲线 2023年10月17日 moment(time).valueOf(),
series=[{ (maxPV > 0 ? maxPV - minPV : minPV - maxPV).toFixed(2),
type: 'candlestick', ]);
name: '箱线图', _minData.push([moment(time).valueOf(), maxPV > 0 ? minPV : maxPV]);
symbol: 'none', }); //当存在othersData的时候,只是单曲线
data: otherData, // xAxis = {type: 'category', data: series[0].data.map(item => moment(item[0]).format('YYYY-MM-DD HH:mm:ss'))};
itemStyle: { xAxis = { type: 'time' };
color: '#FFA200', decorateAxisGridLine(xAxis, showGridLine);
color0: '#44CD00', let _unit = '';
borderColor: '#FFA200', series = series.map((item) => {
borderColor0: '#44CD00', _unit = item.unit ?? '';
item.areaStyle = null;
return { ...item, showSymbol: false };
});
[[..._minData], [..._maxData]].forEach((item, index) => {
series.push({
name: index === 0 ? '周期最小值' : '周期最大值',
type: 'line',
data: item,
lineStyle: {
opacity: 0,
},
...(index !== 0
? {
areaStyle: {
color: series?.[0]?.itemStyle?.color ?? '#65a0d1',
opacity: 0.2,
}, },
}]; }
tooltip = tooltipAccessor(unit); : {}),
} stack: 'confidence-band',
if (chartType === 'lineChart' || lineDataType === '原始曲线') { symbol: 'none',
let _maxData = []; });
let _minData = []; });
let _currentYear = moment().format('YYYY'); tooltip = {
const formatStr = trigger: 'axis',
contrastOption === 'day' formatter: (e) => {
? `${_currentYear}-01-01 HH:mm:00` return `<div>
: `${_currentYear}-01-DD HH:mm:00`; // 用来做同期对比,把日期拉到同一区间
let _maxValues = [];
/**
* 生成泳道图,分两种情况
* 1. 当最大值最小值都是正数时;
* 2. 当最大值小于零时(此时,最小值一定小于零);
*/
dataSource?.[0]?.dataModel.forEach((item) => {
const {firstPV, lastPV, maxPV, minPV, pt} = item;
_maxValues.push(maxPV);
let time = contrast ? moment(pt).format(formatStr) : pt;
_maxData.push([
moment(time).valueOf(),
(maxPV > 0 ? maxPV - minPV : minPV - maxPV).toFixed(2),
]);
_minData.push([moment(time).valueOf(), maxPV > 0 ? minPV : maxPV]);
}); //当存在othersData的时候,只是单曲线
// xAxis = {type: 'category', data: series[0].data.map(item => moment(item[0]).format('YYYY-MM-DD HH:mm:ss'))};
xAxis = {type: 'time'};
decorateAxisGridLine(xAxis, showGridLine);
let _unit = '';
series = series.map((item) => {
_unit = item.unit ?? '';
item.areaStyle = null;
return {...item, showSymbol: false};
});
[[..._minData], [..._maxData]].forEach((item, index) => {
series.push({
name: index === 0 ? '周期最小值' : '周期最大值',
type: 'line',
data: item,
lineStyle: {
opacity: 0,
},
...(index !== 0
? {
areaStyle: {
color: series?.[0]?.itemStyle?.color ?? '#65a0d1',
opacity: 0.2,
},
}
: {}),
stack: 'confidence-band',
symbol: 'none',
});
});
tooltip = {
trigger: 'axis',
formatter: (e) => {
return `<div>
${headTemplate(e[0])} ${headTemplate(e[0])}
<div> <div>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span style="${isMobile() <span style="${
? 'width: ' + isMobile()
handlePx(90, 'px') + ? 'width: ' +
';overflow:hidden;text-overflow:ellipsis;white-space:nowrap' handlePx(90, 'px') +
: '' ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
}">${e[0].seriesName : ''
}</span><span style="display:inline-block;">:</span> }">${
e[0].seriesName
}</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.NORMAL};margin: 0 ${handlePx( <span style="color: ${COLOR.NORMAL};margin: 0 ${handlePx(
5, 5,
'px', 'px',
)} 0 auto;">${e[0]?.value?.[1] ?? '-'}</span> )} 0 auto;">${e[0]?.value?.[1] ?? '-'}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: ${lineDataType === '特征曲线' ? 'flex' : 'none' <div style="display: ${
}; align-items: center;"> lineDataType === '特征曲线' ? 'flex' : 'none'
}; align-items: center;">
<span>周期最小值</span><span style="display:inline-block;">:</span> <span>周期最小值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx( <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(
5, 5,
'px', 'px',
)} 0 auto;">${e?.[1]?.value?.[1] ?? '-'}</span> )} 0 auto;">${e?.[1]?.value?.[1] ?? '-'}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: ${lineDataType === '特征曲线' ? 'flex' : 'none' <div style="display: ${
}; align-items: center;"> lineDataType === '特征曲线' ? 'flex' : 'none'
}; align-items: center;">
<span>周期最大值</span><span style="display:inline-block;">:</span> <span>周期最大值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx( <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(
5, 5,
'px', 'px',
)} 0 auto;">${_maxValues[e?.[2]?.dataIndex] ?? '-'}</span> )} 0 auto;">${_maxValues[e?.[2]?.dataIndex] ?? '-'}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
</div> </div>
</div>`; </div>`;
}, },
}; };
}
// 单曲线需要标记最大值、最小值的情况下,需要增加自定义的series,将最大最小值显示在图表上
if (dataSource?.[0]?.dataModel?.length && chartType === 'lineChart') {
let _customSeries = returnCustomSeries(dataSource);
series.push(_customSeries);
}
} else {
tooltip = tooltipAccessor(
series.map((item) => item.unit),
{contrastOption, contrast},
);
} }
tooltip.timeFormat = tooltipTimeFormat; // 单曲线需要标记最大值、最小值的情况下,需要增加自定义的series,将最大最小值显示在图表上
let _legendData = series if (dataSource?.[0]?.dataModel?.length && chartType === 'lineChart') {
.filter((item) => !['周期最大值', '周期最小值', '自定义'].includes(item.name)) // legend中,过滤掉辅助业务的legend let _customSeries = returnCustomSeries(dataSource);
.map((item) => item.name); series.push(_customSeries);
assignOptions(restOption, xAxis, _legendData, chartType, contrast, contrastOption, config); }
let _options = { } else {
yAxis, tooltip = tooltipAccessor(
grid, series.map((item) => item.unit),
xAxis, { contrastOption, contrast },
series, );
tooltip, }
visualMap, tooltip.timeFormat = tooltipTimeFormat;
...restOption, let _legendData = series
}; .filter((item) => !['周期最大值', '周期最小值', '自定义'].includes(item.name)) // legend中,过滤掉辅助业务的legend
return _options; .map((item) => item.name);
assignOptions(restOption, xAxis, _legendData, chartType, contrast, contrastOption, config);
let _options = {
yAxis,
grid,
xAxis,
series,
tooltip,
visualMap,
...restOption,
};
return _options;
}; };
export default optionGenerator; export default optionGenerator;
const handleDataSource = (dataSource) => { const handleDataSource = (dataSource) => {
let _temp = null; let _temp = null;
let _data = []; let _data = [];
let _dataLength = dataSource[0].dataModel.length; let _dataLength = dataSource[0].dataModel.length;
// handleSpecial2() // handleSpecial2()
dataSource[0].dataModel.forEach((item, index) => { dataSource[0].dataModel.forEach((item, index) => {
if (index === 0) { if (index === 0) {
_data.push(item) _data.push(item);
} else if (index === _dataLength - 1) { } else if (index === _dataLength - 1) {
_data.push(item); _data.push(item);
} else { } else {
if (_temp.pv !== item.pv) { if (_temp.pv !== item.pv) {
_data.push(item); _data.push(item);
} }
} }
_temp = item; _temp = item;
}); });
return _data return _data;
}; };
const returnLegend = (sensorType) => { const returnLegend = (sensorType) => {
const _colorMap = { const _colorMap = {
变频: '#1685ff', 变频: '#1685ff',
工频: '#00d0c7', 工频: '#00d0c7',
运行: '#1685ff', 运行: '#1685ff',
故障: '#ff6b37', 故障: '#ff6b37',
停止: '#666666', 停止: '#666666',
}; };
}; };
const handleSpecial2 = (special, sensorName, sensorType, data1, data2) => { const handleSpecial2 = (special, sensorName, sensorType, data1, data2) => {
let color = ''; let color = '';
let name = ''; let name = '';
let value1 = ''; let value1 = '';
let value2 = ''; let value2 = '';
// 1. valDesc // 1. valDesc
if (sensorType === '状态值') { if (sensorType === '状态值') {
const _colorMap = { const _colorMap = {
变频: '#1685ff', 变频: '#1685ff',
工频: '#00d0c7', 工频: '#00d0c7',
运行: '#1685ff', 运行: '#1685ff',
故障: '#ff6b37', 故障: '#ff6b37',
停止: '#666666', 停止: '#666666',
}; };
let _valDescMap = special.allValDesc[sensorName]?.split(';').reduce((final, cur) => { let _valDescMap = special.allValDesc[sensorName]?.split(';').reduce((final, cur) => {
let _arr = cur.split(':'); let _arr = cur.split(':');
final[_arr[0]] = _arr[1]; final[_arr[0]] = _arr[1];
return final return final;
}, {}); }, {});
name = _valDescMap[data1.pv]; name = _valDescMap[data1.pv];
color = _colorMap[name]; color = _colorMap[name];
} }
//2. 开关量 //2. 开关量
if (sensorType === '开关值') { if (sensorType === '开关值') {
const _switchColorMap = { const _switchColorMap = {
0: '#666666', 0: '#666666',
1: '#1685ff' 1: '#1685ff',
}; };
const _switchNameMap = { const _switchNameMap = {
0: '关', 0: '关',
1: '开' 1: '开',
} };
name = _switchNameMap[data1.pv]; name = _switchNameMap[data1.pv];
color = _switchColorMap[data1.pv]; color = _switchColorMap[data1.pv];
} }
value1 = moment(data1.pt).valueOf(); value1 = moment(data1.pt).valueOf();
value2 = moment(data2.pt).valueOf(); value2 = moment(data2.pt).valueOf();
return {color, value1, value2, name} return { color, value1, value2, name };
}; };
const handleDataToSeries = (special, sensorName, sensorType, data) => { const handleDataToSeries = (special, sensorName, sensorType, data) => {
let _data = []; let _data = [];
let _legend = []; let _legend = [];
data.forEach((item, index) => { data.forEach((item, index) => {
if (index === data.length - 1) return; if (index === data.length - 1) return;
let {color, value1, value2, name} = handleSpecial2(special, sensorName, sensorType, item, data[index + 1]) let { color, value1, value2, name } = handleSpecial2(
if (!_legend.includes(name)) _legend.push(name); special,
_data.push({ sensorName,
itemStyle: {normal: {color}}, sensorType,
name: name, item,
value: [0, value1, value2, `${item.pt}-${data[index + 1].pt}`] data[index + 1],
}); );
if (!_legend.includes(name)) _legend.push(name);
_data.push({
itemStyle: { normal: { color } },
name: name,
value: [0, value1, value2, `${item.pt}-${data[index + 1].pt}`],
}); });
return {data: _data, legend: _legend}; });
return { data: _data, legend: _legend };
}; };
const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contrastOption, smooth, config}) => { const specialTypeChartOptionGenerator = ({
const {special, sensorType} = config; dataSource,
const {allSensorType, allPointAddress} = special; cusOption,
// 处理原始数据,处理数据为后series数据 contrast,
const sensorName = dataSource[0].sensorName; contrastOption,
let _data = handleDataSource(dataSource); smooth,
let {data, legend} = handleDataToSeries(special, sensorName, sensorType, _data); config,
// 1. x/y轴 }) => {
let xAxis = { const { special, sensorType } = config;
type: 'time', const { allSensorType, allPointAddress } = special;
axisLabel: { // 处理原始数据,处理数据为后series数据
formatter: contrast ? (contrastOption === 'month' ? '{dd}日' : '{HH}:{mm}') const sensorName = dataSource[0].sensorName;
: { let _data = handleDataSource(dataSource);
year: '{yyyy}', let { data, legend } = handleDataToSeries(special, sensorName, sensorType, _data);
month: '{MMM}', // 1. x/y轴
day: '{MMM}{d}日', let xAxis = {
hour: '{HH}:{mm}', type: 'time',
minute: '{HH}:{mm}', axisLabel: {
second: '{HH}:{mm}:{ss}', formatter: contrast
none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}', ? contrastOption === 'month'
}, ? '{dd}日'
}, : '{HH}:{mm}'
minorTick: { : {
lineStyle: { year: '{yyyy}',
color: "#e2e2e2" month: '{MMM}',
}, day: '{MMM}{d}日',
show: true, hour: '{HH}:{mm}',
splitNumber: 2 minute: '{HH}:{mm}',
}, second: '{HH}:{mm}:{ss}',
minorSplitLine: { none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}',
lineStyle: { },
color: "#e2e2e2", },
type: "dashed" minorTick: {
}, lineStyle: {
show: true color: '#e2e2e2',
}, },
splitLine: { show: true,
show: true splitNumber: 2,
}, },
minInterval: 3600 * 1000 minorSplitLine: {
}; lineStyle: {
let yAxis = { color: '#e2e2e2',
data: [dataSource[0].sensorName], type: 'dashed',
axisLine: { },
show: true show: true,
}, },
minorTick: { splitLine: {
lineStyle: { show: true,
color: "#e2e2e2" },
}, minInterval: 3600 * 1000,
show: true, };
splitNumber: 2 let yAxis = {
}, data: [dataSource[0].sensorName],
minorSplitLine: { axisLine: {
lineStyle: { show: true,
color: "#e2e2e2", },
type: "dashed" minorTick: {
}, lineStyle: {
show: true color: '#e2e2e2',
}, },
splitLine: { show: true,
show: true splitNumber: 2,
}, },
}; minorSplitLine: {
//2. series lineStyle: {
let series = [ color: '#e2e2e2',
{ type: 'dashed',
type: 'custom', },
renderItem: renderStatusItem, show: true,
itemStyle: { },
opacity: 0.8 splitLine: {
}, show: true,
encode: { },
x: [1, 2], };
y: 0 //2. series
}, let series = [
data {
}, type: 'custom',
...legend.map(item => { renderItem: renderStatusItem,
let _map = { itemStyle: {
变频: '#1685ff', opacity: 0.8,
工频: '#00d0c7', },
运行: '#1685ff', encode: {
故障: '#ff6b37', x: [1, 2],
停止: '#666666', y: 0,
: '#666666', },
: '#1685ff' data,
} },
return { ...legend.map((item) => {
type: 'custom', let _map = {
name: item, 变频: '#1685ff',
color: _map[item], 工频: '#00d0c7',
renderItem: () => { 运行: '#1685ff',
} 故障: '#ff6b37',
} 停止: '#666666',
}) : '#666666',
]; : '#1685ff',
let grid = { };
top: 80, return {
left: 30, type: 'custom',
right: 10, name: item,
bottom: 60, color: _map[item],
containLabel: true renderItem: () => {},
}; };
let legendConfig = { }),
show: true, ];
data: legend, let grid = {
selectedMode: false, top: 80,
right: 10, left: 30,
top: 30, right: 10,
icon: 'rect', bottom: 60,
itemWidth: 14, containLabel: true,
itemHeight: 8, };
itemGap: 20, let legendConfig = {
}; show: true,
let _option = { data: legend,
xAxis, selectedMode: false,
yAxis, right: 10,
grid, top: 30,
series, icon: 'rect',
legend: legendConfig, itemWidth: 14,
tooltip: { itemHeight: 8,
trigger: 'item', itemGap: 20,
formatter: function (params) { };
return params.marker + params.name + ': ' + params?.value?.[3]; let _option = {
} xAxis,
}, yAxis,
dataZoom: [ grid,
{ series,
type: 'slider', legend: legendConfig,
filterMode: 'weakFilter', tooltip: {
showDataShadow: false, trigger: 'item',
labelFormatter: '' formatter: function (params) {
}, return params.marker + params.name + ': ' + params?.value?.[3];
{ },
type: 'inside', },
filterMode: 'weakFilter' dataZoom: [
} {
], type: 'slider',
} filterMode: 'weakFilter',
return _option; showDataShadow: false,
labelFormatter: '',
},
{
type: 'inside',
filterMode: 'weakFilter',
},
],
};
return _option;
}; };
export { export { specialTypeChartOptionGenerator };
specialTypeChartOptionGenerator
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment