Commit 6a5da773 authored by 陈龙's avatar 陈龙

feat: 优化显示

parent 26fbdcef
...@@ -33,7 +33,7 @@ const Demo = () => { ...@@ -33,7 +33,7 @@ const Demo = () => {
<HistoryView deviceParams={deviceParams} defaultModel="curve"/> <HistoryView deviceParams={deviceParams} defaultModel="curve"/>
</div> </div>
<div style={{height: 300}}> <div style={{height: 300}}>
<MobileHistoryChart deviceParams={deviceParams} chartType={'lineChart'}/> <MobileHistoryChart deviceParams={deviceParams} chartType={'boxChart'}/>
</div> </div>
</div> </div>
......
...@@ -40,14 +40,14 @@ const MobileHistoryChart = ( ...@@ -40,14 +40,14 @@ const MobileHistoryChart = (
date = { date = {
dateFrom: moment().format(`${DATE_FORMAT} 00:00:00`), dateFrom: moment().format(`${DATE_FORMAT} 00:00:00`),
dateTo: moment().format(`${DATE_FORMAT} 23:59:59`) dateTo: moment().format(`${DATE_FORMAT} 23:59:59`)
}, },// 默认当天
deviceParams = [], deviceParams = [], // 设备参数,必传
ignoreOutliers = true,
isDilute = true,
needMarkLine = true,
showBoxOption = true, //
chartGrid = true,
chartType='lineChart', // lineChart boxChart chartType='lineChart', // lineChart boxChart
ignoreOutliers = true, // 滤波
isDilute = true, // 抽稀去重
needMarkLine = true,
showBoxOption = true, // 开启箱线图配置,默认开启
chartGrid = true, // 开启网格
} }
) => { ) => {
const [deviceAlarmSchemes, setDeviceAlarmSchemes] = useState(null); const [deviceAlarmSchemes, setDeviceAlarmSchemes] = useState(null);
...@@ -57,7 +57,7 @@ const MobileHistoryChart = ( ...@@ -57,7 +57,7 @@ const MobileHistoryChart = (
const isBoxPlots = const isBoxPlots =
deviceParams?.length === 1 && deviceParams[0]?.sensors?.split(',').length === 1; deviceParams?.length === 1 && deviceParams[0]?.sensors?.split(',').length === 1;
const handleDataThinKey = (diffDays) => { const handleDataThinKey = (diffDays) => {
// 移动端缩放的抽稀一倍 // 移动端缩放的抽稀一倍,需要实际调试
if (diffDays >= 7 && diffDays < 15) { if (diffDays >= 7 && diffDays < 15) {
return {unit: 'h', zoom: '4'}; return {unit: 'h', zoom: '4'};
} else if (diffDays >= 15 && diffDays < 30) { } else if (diffDays >= 15 && diffDays < 30) {
...@@ -69,7 +69,7 @@ const MobileHistoryChart = ( ...@@ -69,7 +69,7 @@ const MobileHistoryChart = (
} else if (diffDays < 2 && diffDays >= 1) { } else if (diffDays < 2 && diffDays >= 1) {
return {unit: 'min', zoom: '60'}; return {unit: 'min', zoom: '60'};
} else { } else {
return {unit: 'min', zoom: '20'}; return {unit: 'min', zoom: '60'};
} }
}; };
......
...@@ -4,25 +4,25 @@ import _, {isArray} from 'lodash'; ...@@ -4,25 +4,25 @@ import _, {isArray} from 'lodash';
/** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */ /** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */
const axisWidth = 40; const axisWidth = 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 ( if (
/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test( /ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(
userAgent userAgent
) )
) { ) {
return true; return true;
} }
return false; return false;
} }
/** /**
* 图表系列名称格式化 * 图表系列名称格式化
...@@ -33,13 +33,13 @@ const isMobile =() => { ...@@ -33,13 +33,13 @@ const isMobile =() => {
* @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;
}; };
/** /**
...@@ -51,16 +51,16 @@ const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => { ...@@ -51,16 +51,16 @@ 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 ?? [];
let _currentYear = moment().format('YYYY'); let _currentYear = moment().format('YYYY');
const formatStr = const formatStr =
contrastOption === 'day' ? `${_currentYear}-01-01 HH:mm:00` : `${_currentYear}-01-DD HH:mm:00`; contrastOption === 'day' ? `${_currentYear}-01-01 HH:mm:00` : `${_currentYear}-01-DD HH:mm:00`;
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];
}); });
}; };
/** /**
...@@ -70,8 +70,8 @@ const dataAccessor = (data, contrast, contrastOption) => { ...@@ -70,8 +70,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;
}; };
/** /**
...@@ -81,110 +81,110 @@ const areaStyleFormatter = (data) => { ...@@ -81,110 +81,110 @@ 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) => {
// 只有一个数据曲线时显示markline // 只有一个数据曲线时显示markline
if (!dataItem || dataSource.length !== 1) return {}; if (!dataItem || dataSource.length !== 1) return {};
const data = []; const data = [];
data.push({ type: 'min', name: '最小: ' }); data.push({type: 'min', name: '最小: '});
data.push({ type: 'max', name: '最大: ' }); data.push({type: 'max', name: '最大: '});
return { return {
symbolSize: 1, symbolSize: 1,
symbolOffset: [0, '50%'], symbolOffset: [0, '50%'],
label: { label: {
formatter: '{b|{b} }{c|{c}}', formatter: '{b|{b} }{c|{c}}',
backgroundColor: backgroundColor:
window.globalConfig && window.globalConfig &&
window.globalConfig && window.globalConfig &&
window.globalConfig.variableTheme?.primaryColor window.globalConfig.variableTheme?.primaryColor
? window.globalConfig.variableTheme.primaryColor ? window.globalConfig.variableTheme.primaryColor
: '#0087F7', : '#0087F7',
borderColor: '#ccc', borderColor: '#ccc',
borderWidth: 1, borderWidth: 1,
borderRadius: 4, borderRadius: 4,
padding: [2, 10], padding: [2, 10],
lineHeight: 22, lineHeight: 22,
position: 'top', position: 'top',
distance: 10, distance: 10,
rich: { rich: {
b: { b: {
color: '#fff', color: '#fff',
}, },
c: { c: {
color: '#fff', color: '#fff',
fontSize: 16, fontSize: 16,
fontWeight: 700, fontWeight: 700,
},
},
}, },
}, data,
}, };
data,
};
}; };
/** /**
...@@ -193,27 +193,27 @@ export const minMaxMarkPoint = (dataItem, index, dataSource) => { ...@@ -193,27 +193,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,
}; };
}; };
/** /**
...@@ -222,35 +222,35 @@ export const decorateAxisGridLine = (axis, showGrid) => { ...@@ -222,35 +222,35 @@ 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),
},
];
hasOffline = true;
} else if (item.pv && hasOffline) {
offlineData.push({
xAxis: new Date(item.pt),
});
datas.push(offlineData);
offlineData = [];
hasOffline = false;
}
});
return {
itemStyle: {
color: '#eee',
}, },
]; 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',
},
data: datas,
};
}; };
/** /**
...@@ -264,105 +264,105 @@ export const offlineArea = (dataItem) => { ...@@ -264,105 +264,105 @@ export const offlineArea = (dataItem) => {
* @param {any} config 额外配置信息 * @param {any} config 额外配置信息
*/ */
const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth, config) => { const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth, config) => {
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 justLine = _.get(config, 'justLine', false); // const justLine = _.get(config, 'justLine', false);
const showBoxOption = _.get(config, 'showBoxOption', false); const showBoxOption = _.get(config, 'showBoxOption', false);
// 自定义属性 // 自定义属性
const restOption = _.pick(cusOption, ['title', 'legend']); const restOption = _.pick(cusOption, ['title', 'legend']);
// 一种指标一个y轴 // 一种指标一个y轴
const yAxisMap = new Map(); const yAxisMap = new Map();
dataSource.forEach((item, index) => { dataSource.forEach((item, index) => {
const { sensorName, unit } = item; const {sensorName, unit} = item;
const key = sensorName; const key = sensorName;
if (!yAxisMap.has(key)) { if (!yAxisMap.has(key)) {
const i = yAxisMap.size; const i = yAxisMap.size;
const axis = { const axis = {
type: 'value', type: 'value',
name: needUnit ? unit : null, name: needUnit ? unit : null,
position: i % 2 === 0 ? 'left' : 'right', position: i % 2 === 0 ? 'left' : 'right',
offset: Math.floor(i / 2) * axisWidth, offset: Math.floor(i / 2) * axisWidth,
axisLabel: { axisLabel: {
formatter: (value) => (value > 100000 ? `${value / 1000}k` : value), formatter: (value) => (value > 100000 ? `${value / 1000}k` : value),
}, },
axisLine: { axisLine: {
show: true, show: true,
}, },
nameTextStyle: { nameTextStyle: {
align: i % 2 === 0 ? 'right' : 'left', align: i % 2 === 0 ? 'right' : 'left',
}, },
minorTick: { minorTick: {
lineStyle: { lineStyle: {
color: '#e2e2e2', color: '#e2e2e2',
}, },
}, },
minorSplitLine: { minorSplitLine: {
lineStyle: { lineStyle: {
color: '#e2e2e2', color: '#e2e2e2',
type: 'dashed', type: 'dashed',
}, },
}, },
}; };
yAxisMap.set(key, axis); yAxisMap.set(key, axis);
} }
// 曲线居中 // 曲线居中
if (curveCenter && item.dataModel && item.dataModel.length > 0) { if (curveCenter && item.dataModel && item.dataModel.length > 0) {
const [min, max] = minMax(item); const [min, max] = minMax(item);
const axis = yAxisMap.get(key); const axis = yAxisMap.get(key);
axis.min = axis.min === void 0 ? min : Math.min(min, axis.min); axis.min = axis.min === void 0 ? min : Math.min(min, axis.min);
axis.max = axis.max === void 0 ? max : Math.max(max, axis.max); axis.max = axis.max === void 0 ? max : Math.max(max, axis.max);
} }
// 网格显示 // 网格显示
const axis = yAxisMap.get(key); const axis = yAxisMap.get(key);
decorateAxisGridLine(axis, showGridLine); decorateAxisGridLine(axis, showGridLine);
}); });
const yAxis = yAxisMap.size > 0 ? [...yAxisMap.values()] : { type: 'value' }; const yAxis = yAxisMap.size > 0 ? [...yAxisMap.values()] : {type: 'value'};
// 根据y轴个数调整边距 // 根据y轴个数调整边距
const leftNum = Math.ceil(yAxisMap.size / 2); const leftNum = Math.ceil(yAxisMap.size / 2);
const rightNum = Math.floor(yAxisMap.size / 2); const rightNum = Math.floor(yAxisMap.size / 2);
const grid = { const grid = {
top: needUnit ? 80 : 60, top: needUnit ? 80 : 60,
left: 10 + leftNum * axisWidth, left: 10 + leftNum * axisWidth,
right: rightNum === 0 ? 20 : rightNum * axisWidth, right: rightNum === 0 ? 20 : rightNum * axisWidth,
bottom: 60, bottom: 60,
}; };
const headTemplate = (param) => { const headTemplate = (param) => {
if (!param) return ''; if (!param) return '';
const { name, axisValueLabel, axisType, axisValue } = param; const {name, axisValueLabel, axisType, axisValue} = param;
const timeFormat = 'YYYY-MM-DD HH:mm:ss'; const timeFormat = '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: 5px; padding-bottom: 5px;">${text}</div>`; return `<div style="border-bottom: 1px solid #F0F0F0; color: #808080; margin-bottom: 5px; padding-bottom: 5px;">${text}</div>`;
}; };
const seriesTemplate = (param, unit) => { const seriesTemplate = (param, unit) => {
if (!param) return ''; if (!param) return '';
const { value, encode } = param; const {value, encode} = param;
// const val = value[encode.y[0]]; // const val = value[encode.y[0]];
const _unit = unit || 'Mpa'; const _unit = unit || 'Mpa';
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>${param.seriesName}</span><span style="display:inline-block;">:</span> <span>${isMobile() ? '实际值' : param.seriesName}</span><span style="display:inline-block;">:</span>
<span style="color:${color};margin: 0 5px 0 auto;">${value?.toFixed(3) ?? '-'}</span> <span style="color:${color};margin: 0 5px 0 auto;">${value?.toFixed(3) ?? '-'}</span>
<span style="font-size: 12px;">${_unit}</span> <span style="font-size: 12px;">${_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>${param.seriesName}</span><span style="display:inline-block;">:</span> <span>${isMobile() ? '实际值' : param.seriesName}</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 5px 0 auto;">${value[1] ?? '-'}</span> <span style="color: ${COLOR.AVG};margin: 0 5px 0 auto;">${value[1] ?? '-'}</span>
<span style="font-size: 12px;">${_unit}</span> <span style="font-size: 12px;">${_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 5px 0 auto;">${value[1] ?? '-'}</span> <span style="color: ${COLOR.AVG};margin: 0 5px 0 auto;">${value[1] ?? '-'}</span>
...@@ -384,251 +384,251 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth ...@@ -384,251 +384,251 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
<span style="font-size: 12px;">${_unit}</span> <span style="font-size: 12px;">${_unit}</span>
</div> </div>
`; `;
}; };
const tooltipAccessor = (unit) => { const tooltipAccessor = (unit) => {
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]); tooltipHeader = headTemplate(params[0]);
params.forEach((param) => { params.forEach((param) => {
tooltipContent += seriesTemplate(param, unit); tooltipContent += seriesTemplate(param, unit);
}); });
} else { } else {
tooltipHeader = headTemplate(params); tooltipHeader = headTemplate(params);
tooltipContent += seriesTemplate(params, unit); tooltipContent += seriesTemplate(params, unit);
} }
return ` return `
<div> <div>
${tooltipHeader} ${tooltipHeader}
<div>${tooltipContent}</div> <div>${tooltipContent}</div>
</div> </div>
`; `;
}, },
};
}; };
}; // 根据"指标名称"分类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 = []; let series = dataSource
let series = dataSource .filter((item) => {
.filter((item) => { if (item.sensorName === '是否在线') {
if (item.sensorName === '是否在线') { _offlineData.push(item);
_offlineData.push(item); }
} return item.sensorName !== '是否在线';
return item.sensorName !== '是否在线';
})
.map((item, index) => {
const { sensorName, unit } = item;
const name = nameFormatter(item, contrast, contrastOption, nameWithSensor);
const data = dataAccessor(item, contrast, contrastOption);
const type = 'line';
const areaStyle = areaStyleFormatter(item);
const yAxisIndex = yAxisInterator.get(sensorName);
const markLine = showMarkLine
? alarmMarkLine(item, index, dataSource, deviceAlarmSchemes)
: {};
const markPoint = showPoint ? minMaxMarkPoint(item, index, dataSource) : {};
let markArea = null;
// 需求变更:设备离线改用“是否在线”的数据,离线的状态标记的数据用该部分的数据。 2023年4月25日09:36:55
let _offlineAreasData = _offlineData
.map((item) => {
let _item = { ...item };
_item.dataModel = item.dataModel.map((d) => {
let _d = { ...d };
_d.pv = 0;
return _d;
});
return _item;
}) })
.find((offline) => offline.stationCode === item.stationCode); .map((item, index) => {
let offlineAreas = offlineArea(_offlineAreasData); const {sensorName, unit} = item;
if (offlineAreas.data?.length) { const name = nameFormatter(item, contrast, contrastOption, nameWithSensor);
restOption.markArea = null; const data = dataAccessor(item, contrast, contrastOption);
markArea = offlineAreas; const type = 'line';
} const areaStyle = areaStyleFormatter(item);
return { const yAxisIndex = yAxisInterator.get(sensorName);
notMerge: true, const markLine = showMarkLine
name, ? alarmMarkLine(item, index, dataSource, deviceAlarmSchemes)
type, : {};
data, const markPoint = showPoint ? minMaxMarkPoint(item, index, dataSource) : {};
areaStyle, let markArea = null;
yAxisIndex, // 需求变更:设备离线改用“是否在线”的数据,离线的状态标记的数据用该部分的数据。 2023年4月25日09:36:55
smooth, let _offlineAreasData = _offlineData
unit, .map((item) => {
markLine, let _item = {...item};
markPoint, _item.dataModel = item.dataModel.map((d) => {
markArea, let _d = {...d};
}; _d.pv = 0;
}); return _d;
// 由于series更新后,没有的数据曲线仍然停留在图表区上,导致图表可视区范围有问题 });
const min = Math.min( return _item;
...series.map((item) => item.data?.[0]?.[0]).filter((item) => item !== undefined), })
); .find((offline) => offline.stationCode === item.stationCode);
const max = Math.max( let offlineAreas = offlineArea(_offlineAreasData);
...series if (offlineAreas.data?.length) {
.map((item) => item.data?.[item.data.length - 1]?.[0]) restOption.markArea = null;
.filter((item) => item !== undefined), markArea = offlineAreas;
); }
let xAxis = { type: 'time', min, max }; return {
decorateAxisGridLine(xAxis, showGridLine); notMerge: true,
const tooltipTimeFormat = !contrast name,
? 'YYYY-MM-DD HH:mm:ss' type,
: contrastOption === 'day' data,
? 'HH:mm' areaStyle,
: 'DD HH:mm'; yAxisIndex,
let tooltip = { smooth,
timeFormat: tooltipTimeFormat, unit,
// trigger: 'axis', markLine,
// axisPointer: { markPoint,
// type: 'cross' markArea,
// } };
};
// 增加箱线图的逻辑,单曲线才存在
if (chartType && showBoxOption) {
if (chartType === 'boxChart') {
const otherData =
dataSource?.[0]?.dataModel.map((item) => {
const { firstPV, lastPV, maxPV, minPV, pt } = item;
return [moment(pt).valueOf(), firstPV, lastPV, 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) => {
if (item.unit) unit = item.unit;
let _item = { ...item, symbol: 'none' };
/* _item.data = _item?.data?.map(d => {
return d[1] || null
}) || [];*/
return _item;
});
series.push({
type: 'candlestick',
name: '箱线图',
symbol: 'none',
data: otherData,
itemStyle: {
color: '#FFA200',
color0: '#44CD00',
borderColor: '#FFA200',
borderColor0: '#44CD00',
},
});
tooltip = tooltipAccessor(unit);
} else {
let _maxData = [];
let _minData = [];
let _currentYear = moment().format('YYYY');
const formatStr =
contrastOption === 'day'
? `${_currentYear}-01-01 HH:mm:00`
: `${_currentYear}-01-DD HH:mm:00`; // 用来做同期对比,把日期拉到同一区间
let _maxValues = [];
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 - minPV).toFixed(2)]);
_minData.push([moment(time).valueOf(), minPV]);
}); //当存在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;
return {...item, symbol: 'none'};
});
[[..._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',
}); });
}); // 由于series更新后,没有的数据曲线仍然停留在图表区上,导致图表可视区范围有问题
tooltip = { const min = Math.min(
formatter: (e) => { ...series.map((item) => item.data?.[0]?.[0]).filter((item) => item !== undefined),
return `<div> );
const max = Math.max(
...series
.map((item) => item.data?.[item.data.length - 1]?.[0])
.filter((item) => item !== undefined),
);
let xAxis = {type: 'time', min, max};
decorateAxisGridLine(xAxis, showGridLine);
const tooltipTimeFormat = !contrast
? 'YYYY-MM-DD HH:mm:ss'
: contrastOption === 'day'
? 'HH:mm'
: 'DD HH:mm';
let tooltip = {
timeFormat: tooltipTimeFormat,
// trigger: 'axis',
// axisPointer: {
// type: 'cross'
// }
};
// 增加箱线图的逻辑,单曲线才存在
if (chartType && showBoxOption) {
if (chartType === 'boxChart') {
const otherData =
dataSource?.[0]?.dataModel.map((item) => {
const {firstPV, lastPV, maxPV, minPV, pt} = item;
return [moment(pt).valueOf(), firstPV, lastPV, 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) => {
if (item.unit) unit = item.unit;
let _item = {...item, symbol: 'none'};
/* _item.data = _item?.data?.map(d => {
return d[1] || null
}) || [];*/
return _item;
});
series.push({
type: 'candlestick',
name: '箱线图',
symbol: 'none',
data: otherData,
itemStyle: {
color: '#FFA200',
color0: '#44CD00',
borderColor: '#FFA200',
borderColor0: '#44CD00',
},
});
tooltip = tooltipAccessor(unit);
} else {
let _maxData = [];
let _minData = [];
let _currentYear = moment().format('YYYY');
const formatStr =
contrastOption === 'day'
? `${_currentYear}-01-01 HH:mm:00`
: `${_currentYear}-01-DD HH:mm:00`; // 用来做同期对比,把日期拉到同一区间
let _maxValues = [];
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 - minPV).toFixed(2)]);
_minData.push([moment(time).valueOf(), minPV]);
}); //当存在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;
return {...item, symbol: 'none'};
});
[[..._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 = {
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>${ <span>${
isMobile()?'当前值':e[0].seriesName isMobile() ? '当前值' : e[0].seriesName
}</span><span style="display:inline-block;">:</span> }</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.NORMAL};margin: 0 5px 0 auto;">${ <span style="color: ${COLOR.NORMAL};margin: 0 5px 0 auto;">${
e[0]?.value?.[1] ?? '-' e[0]?.value?.[1] ?? '-'
}</span> }</span>
<span style="font-size: 12px;">${_unit}</span> <span style="font-size: 12px;">${_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 5px 0 auto;">${ <span style="color: ${COLOR.AVG};margin: 0 5px 0 auto;">${
e[1]?.value?.[1] ?? '-' e[1]?.value?.[1] ?? '-'
}</span> }</span>
<span style="font-size: 12px;">${_unit}</span> <span style="font-size: 12px;">${_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 5px 0 auto;">${ <span style="color: ${COLOR.AVG};margin: 0 5px 0 auto;">${
_maxValues[e[2].dataIndex] ?? '-' _maxValues[e[2].dataIndex] ?? '-'
}</span> }</span>
<span style="font-size: 12px;">${_unit}</span> <span style="font-size: 12px;">${_unit}</span>
</div> </div>
</div> </div>
</div>`; </div>`;
}, },
}; };
}
} }
} restOption.dataZoom = [
restOption.dataZoom = [ {
{ show: true,
show: true, bottom: 10,
bottom: 10, start: 0,
start: 0, end: 100,
end: 100, height: 28,
height: 28, type: 'inside',
type: 'inside', zoomOnMouseWheel: true,
zoomOnMouseWheel: true, },
}, {
{ show: true,
show: true, bottom: 10,
bottom: 10, start: 0,
start: 0, end: 100,
end: 100, height: 28,
height: 28, type: 'slider',
type: 'slider', zoomOnMouseWheel: true,
zoomOnMouseWheel: true, },
}, ];
]; xAxis.minInterval = 3600 * 1 * 1000;
xAxis.minInterval = 3600 * 1 * 1000; return {
return { yAxis,
yAxis, grid,
grid, xAxis,
xAxis, series,
series, tooltip,
tooltip, ...restOption,
...restOption, };
};
}; };
export default optionGenerator; export default optionGenerator;
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