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

feat: 优化显示

parent 26fbdcef
......@@ -33,7 +33,7 @@ const Demo = () => {
<HistoryView deviceParams={deviceParams} defaultModel="curve"/>
</div>
<div style={{height: 300}}>
<MobileHistoryChart deviceParams={deviceParams} chartType={'lineChart'}/>
<MobileHistoryChart deviceParams={deviceParams} chartType={'boxChart'}/>
</div>
</div>
......
......@@ -40,14 +40,14 @@ const MobileHistoryChart = (
date = {
dateFrom: moment().format(`${DATE_FORMAT} 00:00:00`),
dateTo: moment().format(`${DATE_FORMAT} 23:59:59`)
},
deviceParams = [],
ignoreOutliers = true,
isDilute = true,
needMarkLine = true,
showBoxOption = true, //
chartGrid = true,
},// 默认当天
deviceParams = [], // 设备参数,必传
chartType='lineChart', // lineChart boxChart
ignoreOutliers = true, // 滤波
isDilute = true, // 抽稀去重
needMarkLine = true,
showBoxOption = true, // 开启箱线图配置,默认开启
chartGrid = true, // 开启网格
}
) => {
const [deviceAlarmSchemes, setDeviceAlarmSchemes] = useState(null);
......@@ -57,7 +57,7 @@ const MobileHistoryChart = (
const isBoxPlots =
deviceParams?.length === 1 && deviceParams[0]?.sensors?.split(',').length === 1;
const handleDataThinKey = (diffDays) => {
// 移动端缩放的抽稀一倍
// 移动端缩放的抽稀一倍,需要实际调试
if (diffDays >= 7 && diffDays < 15) {
return {unit: 'h', zoom: '4'};
} else if (diffDays >= 15 && diffDays < 30) {
......@@ -69,7 +69,7 @@ const MobileHistoryChart = (
} else if (diffDays < 2 && diffDays >= 1) {
return {unit: 'min', zoom: '60'};
} else {
return {unit: 'min', zoom: '20'};
return {unit: 'min', zoom: '60'};
}
};
......
......@@ -4,25 +4,25 @@ import _, {isArray} from 'lodash';
/** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */
const axisWidth = 40;
const COLOR = {
NORMAL: '#1685FF',
UPER: '#fa8c16',
UPUPER: '#FF0000',
// LOWER: '#13c2c2',
// LOWLOWER: '#2f54eb',
LOWER: '#fa8c16',
LOWLOWER: '#FF0000',
AVG: '#00B8B1',
NORMAL: '#1685FF',
UPER: '#fa8c16',
UPUPER: '#FF0000',
// LOWER: '#13c2c2',
// LOWLOWER: '#2f54eb',
LOWER: '#fa8c16',
LOWLOWER: '#FF0000',
AVG: '#00B8B1',
};
const isMobile =() => {
const userAgent = navigator.userAgent.toLowerCase();
if (
/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(
userAgent
)
) {
return true;
}
return false;
const isMobile = () => {
const userAgent = navigator.userAgent.toLowerCase();
if (
/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(
userAgent
)
) {
return true;
}
return false;
}
/**
* 图表系列名称格式化
......@@ -33,13 +33,13 @@ const isMobile =() => {
* @returns
*/
const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => {
const { equipmentName, sensorName, unit, dataModel, dateFrom, dateTo } = data;
let name = nameWithSensor ? `${equipmentName}-${sensorName}` : equipmentName;
if (contrast) {
const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, '');
name = `${name}-${time}`;
}
return name;
const {equipmentName, sensorName, unit, dataModel, dateFrom, dateTo} = data;
let name = nameWithSensor ? `${equipmentName}-${sensorName}` : equipmentName;
if (contrast) {
const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, '');
name = `${name}-${time}`;
}
return name;
};
/**
......@@ -51,16 +51,16 @@ const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => {
* @returns 图表系列数据, [[DateTime, value]]
*/
const dataAccessor = (data, contrast, contrastOption) => {
const dataModel = data?.dataModel ?? [];
let _currentYear = moment().format('YYYY');
const formatStr =
contrastOption === 'day' ? `${_currentYear}-01-01 HH:mm:00` : `${_currentYear}-01-DD HH:mm:00`;
return dataModel
.filter((item) => item.sensorName !== '是否在线')
.map((item) => {
const time = contrast ? moment(item.pt).format(formatStr) : item.pt;
return [moment(time).valueOf(), item.pv];
});
const dataModel = data?.dataModel ?? [];
let _currentYear = moment().format('YYYY');
const formatStr =
contrastOption === 'day' ? `${_currentYear}-01-01 HH:mm:00` : `${_currentYear}-01-DD HH:mm:00`;
return dataModel
.filter((item) => item.sensorName !== '是否在线')
.map((item) => {
const time = contrast ? moment(item.pt).format(formatStr) : item.pt;
return [moment(time).valueOf(), item.pv];
});
};
/**
......@@ -70,8 +70,8 @@ const dataAccessor = (data, contrast, contrastOption) => {
* @returns Null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图.
*/
const areaStyleFormatter = (data) => {
const { sensorName } = data;
return sensorName && sensorName.indexOf('流量') > -1 ? {} : null;
const {sensorName} = data;
return sensorName && sensorName.indexOf('流量') > -1 ? {} : null;
};
/**
......@@ -81,110 +81,110 @@ const areaStyleFormatter = (data) => {
* @returns
*/
const minMax = (data) => {
const { dataModel } = data;
let min = Number.MAX_SAFE_INTEGER;
let max = Number.MIN_SAFE_INTEGER;
dataModel.forEach((item) => {
min = Math.min(min, item.pv ?? 0);
max = Math.max(max, item.pv ?? 0);
});
return [min, max];
const {dataModel} = data;
let min = Number.MAX_SAFE_INTEGER;
let max = Number.MIN_SAFE_INTEGER;
dataModel.forEach((item) => {
min = Math.min(min, item.pv ?? 0);
max = Math.max(max, item.pv ?? 0);
});
return [min, max];
};
const markLineItem = (name, value, color) => {
return {
name: name,
yAxis: value,
value: value,
lineStyle: {
color: color || '#000',
},
label: {
position: 'insideEndTop',
color: color || '#000',
formatter: function () {
return `${name}:${value}`;
},
},
};
return {
name: name,
yAxis: value,
value: value,
lineStyle: {
color: color || '#000',
},
label: {
position: 'insideEndTop',
color: color || '#000',
formatter: function () {
return `${name}:${value}`;
},
},
};
};
export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
// 只有一个数据曲线时显示markline
if (!dataItem || !schemes || dataSource.length !== 1) return {};
const { deviceType, stationCode, sensorName, decimalPoint } = dataItem;
const curSchemes = schemes.filter(
(item) =>
item.deviceCode === stationCode &&
item.sensorName === sensorName &&
item.valueType === '直接取值',
);
const data = [];
curSchemes.forEach((scheme) => {
const { hLimit, hhLimit, lLimit, llLimit } = scheme;
lLimit !== null && lLimit !== void 0 && data.push(markLineItem('低限', lLimit, '#fa8c16'));
hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16'));
llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000'));
hhLimit !== null && hhLimit !== void 0 && data.push(markLineItem('高高限', hhLimit, '#FF0000'));
});
data.push({
name: '平均线',
type: 'average',
lineStyle: {
color: '#00b8b1',
type: 'solid',
},
label: {
position: 'insideEndTop',
color: '#00b8b1',
formatter: function (param) {
return `平均值:${param.value}`;
},
},
});
return {
symbol: ['none', 'none'],
data,
};
// 只有一个数据曲线时显示markline
if (!dataItem || !schemes || dataSource.length !== 1) return {};
const {deviceType, stationCode, sensorName, decimalPoint} = dataItem;
const curSchemes = schemes.filter(
(item) =>
item.deviceCode === stationCode &&
item.sensorName === sensorName &&
item.valueType === '直接取值',
);
const data = [];
curSchemes.forEach((scheme) => {
const {hLimit, hhLimit, lLimit, llLimit} = scheme;
lLimit !== null && lLimit !== void 0 && data.push(markLineItem('低限', lLimit, '#fa8c16'));
hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16'));
llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000'));
hhLimit !== null && hhLimit !== void 0 && data.push(markLineItem('高高限', hhLimit, '#FF0000'));
});
data.push({
name: '平均线',
type: 'average',
lineStyle: {
color: '#00b8b1',
type: 'solid',
},
label: {
position: 'insideEndTop',
color: '#00b8b1',
formatter: function (param) {
return `平均值:${param.value}`;
},
},
});
return {
symbol: ['none', 'none'],
data,
};
};
export const minMaxMarkPoint = (dataItem, index, dataSource) => {
// 只有一个数据曲线时显示markline
if (!dataItem || dataSource.length !== 1) return {};
const data = [];
data.push({ type: 'min', name: '最小: ' });
data.push({ type: 'max', name: '最大: ' });
return {
symbolSize: 1,
symbolOffset: [0, '50%'],
label: {
formatter: '{b|{b} }{c|{c}}',
backgroundColor:
window.globalConfig &&
window.globalConfig &&
window.globalConfig.variableTheme?.primaryColor
? window.globalConfig.variableTheme.primaryColor
: '#0087F7',
borderColor: '#ccc',
borderWidth: 1,
borderRadius: 4,
padding: [2, 10],
lineHeight: 22,
position: 'top',
distance: 10,
rich: {
b: {
color: '#fff',
},
c: {
color: '#fff',
fontSize: 16,
fontWeight: 700,
// 只有一个数据曲线时显示markline
if (!dataItem || dataSource.length !== 1) return {};
const data = [];
data.push({type: 'min', name: '最小: '});
data.push({type: 'max', name: '最大: '});
return {
symbolSize: 1,
symbolOffset: [0, '50%'],
label: {
formatter: '{b|{b} }{c|{c}}',
backgroundColor:
window.globalConfig &&
window.globalConfig &&
window.globalConfig.variableTheme?.primaryColor
? window.globalConfig.variableTheme.primaryColor
: '#0087F7',
borderColor: '#ccc',
borderWidth: 1,
borderRadius: 4,
padding: [2, 10],
lineHeight: 22,
position: 'top',
distance: 10,
rich: {
b: {
color: '#fff',
},
c: {
color: '#fff',
fontSize: 16,
fontWeight: 700,
},
},
},
},
},
data,
};
data,
};
};
/**
......@@ -193,27 +193,27 @@ export const minMaxMarkPoint = (dataItem, index, dataSource) => {
* @param {any} axis
*/
export const decorateAxisGridLine = (axis, showGrid) => {
if (!axis) return;
axis.minorTick = {
lineStyle: {
color: '#e2e2e2',
},
...(axis.minorTick || {}),
show: showGrid,
splitNumber: 2,
};
axis.minorSplitLine = {
lineStyle: {
color: '#e2e2e2',
type: 'dashed',
},
...(axis.minorSplitLine || {}),
show: showGrid,
};
axis.splitLine = {
...(axis.splitLine || {}),
show: showGrid,
};
if (!axis) return;
axis.minorTick = {
lineStyle: {
color: '#e2e2e2',
},
...(axis.minorTick || {}),
show: showGrid,
splitNumber: 2,
};
axis.minorSplitLine = {
lineStyle: {
color: '#e2e2e2',
type: 'dashed',
},
...(axis.minorSplitLine || {}),
show: showGrid,
};
axis.splitLine = {
...(axis.splitLine || {}),
show: showGrid,
};
};
/**
......@@ -222,35 +222,35 @@ export const decorateAxisGridLine = (axis, showGrid) => {
* @param {any} dataItem
*/
export const offlineArea = (dataItem) => {
if (!dataItem) return {};
const { dataModel } = dataItem;
let datas = new Array();
let offlineData = [];
let hasOffline = false;
dataModel.forEach((item, index) => {
if (!item.pv && !hasOffline) {
offlineData = [
{
name: '离线',
xAxis: new Date(item.pt),
if (!dataItem) return {};
const {dataModel} = dataItem;
let datas = new Array();
let offlineData = [];
let hasOffline = false;
dataModel.forEach((item, index) => {
if (!item.pv && !hasOffline) {
offlineData = [
{
name: '离线',
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',
},
];
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,
};
data: datas,
};
};
/**
......@@ -264,105 +264,105 @@ export const offlineArea = (dataItem) => {
* @param {any} config 额外配置信息
*/
const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth, config) => {
const needUnit = _.get(config, 'needUnit', false);
const curveCenter = _.get(config, 'curveCenter', false);
const nameWithSensor = _.get(config, 'nameWithSensor', true);
const showGridLine = _.get(config, 'showGridLine', true);
const showMarkLine = _.get(config, 'showMarkLine', false);
const showPoint = _.get(config, 'showPoint', false);
const deviceAlarmSchemes = _.get(config, 'deviceAlarmSchemes', []);
const chartType = _.get(config, 'chartType', null);
// const justLine = _.get(config, 'justLine', false);
const showBoxOption = _.get(config, 'showBoxOption', false);
// 自定义属性
const restOption = _.pick(cusOption, ['title', 'legend']);
// 一种指标一个y轴
const yAxisMap = new Map();
dataSource.forEach((item, index) => {
const { sensorName, unit } = item;
const key = sensorName;
const needUnit = _.get(config, 'needUnit', false);
const curveCenter = _.get(config, 'curveCenter', false);
const nameWithSensor = _.get(config, 'nameWithSensor', true);
const showGridLine = _.get(config, 'showGridLine', true);
const showMarkLine = _.get(config, 'showMarkLine', false);
const showPoint = _.get(config, 'showPoint', false);
const deviceAlarmSchemes = _.get(config, 'deviceAlarmSchemes', []);
const chartType = _.get(config, 'chartType', null);
// const justLine = _.get(config, 'justLine', false);
const showBoxOption = _.get(config, 'showBoxOption', false);
// 自定义属性
const restOption = _.pick(cusOption, ['title', 'legend']);
// 一种指标一个y轴
const yAxisMap = new Map();
dataSource.forEach((item, index) => {
const {sensorName, unit} = item;
const key = sensorName;
if (!yAxisMap.has(key)) {
const i = yAxisMap.size;
const axis = {
type: 'value',
name: needUnit ? unit : null,
position: i % 2 === 0 ? 'left' : 'right',
offset: Math.floor(i / 2) * axisWidth,
axisLabel: {
formatter: (value) => (value > 100000 ? `${value / 1000}k` : value),
},
axisLine: {
show: true,
},
nameTextStyle: {
align: i % 2 === 0 ? 'right' : 'left',
},
minorTick: {
lineStyle: {
color: '#e2e2e2',
},
},
minorSplitLine: {
lineStyle: {
color: '#e2e2e2',
type: 'dashed',
},
},
};
yAxisMap.set(key, axis);
}
if (!yAxisMap.has(key)) {
const i = yAxisMap.size;
const axis = {
type: 'value',
name: needUnit ? unit : null,
position: i % 2 === 0 ? 'left' : 'right',
offset: Math.floor(i / 2) * axisWidth,
axisLabel: {
formatter: (value) => (value > 100000 ? `${value / 1000}k` : value),
},
axisLine: {
show: true,
},
nameTextStyle: {
align: i % 2 === 0 ? 'right' : 'left',
},
minorTick: {
lineStyle: {
color: '#e2e2e2',
},
},
minorSplitLine: {
lineStyle: {
color: '#e2e2e2',
type: 'dashed',
},
},
};
yAxisMap.set(key, axis);
}
// 曲线居中
if (curveCenter && item.dataModel && item.dataModel.length > 0) {
const [min, max] = minMax(item);
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);
}
// 曲线居中
if (curveCenter && item.dataModel && item.dataModel.length > 0) {
const [min, max] = minMax(item);
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 yAxis = yAxisMap.size > 0 ? [...yAxisMap.values()] : { type: 'value' };
// 网格显示
const axis = yAxisMap.get(key);
decorateAxisGridLine(axis, showGridLine);
});
const yAxis = yAxisMap.size > 0 ? [...yAxisMap.values()] : {type: 'value'};
// 根据y轴个数调整边距
const leftNum = Math.ceil(yAxisMap.size / 2);
const rightNum = Math.floor(yAxisMap.size / 2);
const grid = {
top: needUnit ? 80 : 60,
left: 10 + leftNum * axisWidth,
right: rightNum === 0 ? 20 : rightNum * axisWidth,
bottom: 60,
};
const headTemplate = (param) => {
if (!param) return '';
const { name, axisValueLabel, axisType, axisValue } = param;
const timeFormat = 'YYYY-MM-DD HH:mm:ss';
const text =
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>`;
};
const seriesTemplate = (param, unit) => {
if (!param) return '';
const { value, encode } = param;
// const val = value[encode.y[0]];
const _unit = unit || 'Mpa';
const color = '#008CFF';
if (!isArray(value))
return ` <div style="display: flex; align-items: center;">
<span>${param.seriesName}</span><span style="display:inline-block;">:</span>
// 根据y轴个数调整边距
const leftNum = Math.ceil(yAxisMap.size / 2);
const rightNum = Math.floor(yAxisMap.size / 2);
const grid = {
top: needUnit ? 80 : 60,
left: 10 + leftNum * axisWidth,
right: rightNum === 0 ? 20 : rightNum * axisWidth,
bottom: 60,
};
const headTemplate = (param) => {
if (!param) return '';
const {name, axisValueLabel, axisType, axisValue} = param;
const timeFormat = 'YYYY-MM-DD HH:mm:ss';
const text =
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>`;
};
const seriesTemplate = (param, unit) => {
if (!param) return '';
const {value, encode} = param;
// const val = value[encode.y[0]];
const _unit = unit || 'Mpa';
const color = '#008CFF';
if (!isArray(value))
return ` <div style="display: flex; align-items: center;">
<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="font-size: 12px;">${_unit}</span>
</div>`;
return param.componentSubType !== 'candlestick'
? `<div style="display: flex; align-items: center;">
<span>${param.seriesName}</span><span style="display:inline-block;">:</span>
return param.componentSubType !== 'candlestick'
? `<div style="display: flex; align-items: center;">
<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="font-size: 12px;">${_unit}</span>
</div>`
: `
: `
<div style="display: flex; align-items: center;">
<span>首值</span><span style="display:inline-block;">:</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
<span style="font-size: 12px;">${_unit}</span>
</div>
`;
};
const tooltipAccessor = (unit) => {
return {
formatter: function (params, ticket, callback) {
let tooltipHeader = '';
let tooltipContent = '';
if (isArray(params)) {
tooltipHeader = headTemplate(params[0]);
params.forEach((param) => {
tooltipContent += seriesTemplate(param, unit);
});
} else {
tooltipHeader = headTemplate(params);
tooltipContent += seriesTemplate(params, unit);
}
return `
};
const tooltipAccessor = (unit) => {
return {
formatter: function (params, ticket, callback) {
let tooltipHeader = '';
let tooltipContent = '';
if (isArray(params)) {
tooltipHeader = headTemplate(params[0]);
params.forEach((param) => {
tooltipContent += seriesTemplate(param, unit);
});
} else {
tooltipHeader = headTemplate(params);
tooltipContent += seriesTemplate(params, unit);
}
return `
<div>
${tooltipHeader}
<div>${tooltipContent}</div>
</div>
`;
},
},
};
};
};
// 根据"指标名称"分类yAxis
const yAxisInterator = (() => {
const map = new Map();
let current = -1;
const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name));
return { get };
})();
let _offlineData = [];
let series = dataSource
.filter((item) => {
if (item.sensorName === '是否在线') {
_offlineData.push(item);
}
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;
// 根据"指标名称"分类yAxis
const yAxisInterator = (() => {
const map = new Map();
let current = -1;
const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name));
return {get};
})();
let _offlineData = [];
let series = dataSource
.filter((item) => {
if (item.sensorName === '是否在线') {
_offlineData.push(item);
}
return item.sensorName !== '是否在线';
})
.find((offline) => offline.stationCode === item.stationCode);
let offlineAreas = offlineArea(_offlineAreasData);
if (offlineAreas.data?.length) {
restOption.markArea = null;
markArea = offlineAreas;
}
return {
notMerge: true,
name,
type,
data,
areaStyle,
yAxisIndex,
smooth,
unit,
markLine,
markPoint,
markArea,
};
});
// 由于series更新后,没有的数据曲线仍然停留在图表区上,导致图表可视区范围有问题
const min = Math.min(
...series.map((item) => item.data?.[0]?.[0]).filter((item) => item !== undefined),
);
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',
.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);
let offlineAreas = offlineArea(_offlineAreasData);
if (offlineAreas.data?.length) {
restOption.markArea = null;
markArea = offlineAreas;
}
return {
notMerge: true,
name,
type,
data,
areaStyle,
yAxisIndex,
smooth,
unit,
markLine,
markPoint,
markArea,
};
});
});
tooltip = {
formatter: (e) => {
return `<div>
// 由于series更新后,没有的数据曲线仍然停留在图表区上,导致图表可视区范围有问题
const min = Math.min(
...series.map((item) => item.data?.[0]?.[0]).filter((item) => item !== undefined),
);
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])}
<div>
<div style="display: flex; align-items: center;">
<span>${
isMobile()?'当前值':e[0].seriesName
}</span><span style="display:inline-block;">:</span>
isMobile() ? '当前值' : e[0].seriesName
}</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.NORMAL};margin: 0 5px 0 auto;">${
e[0]?.value?.[1] ?? '-'
}</span>
e[0]?.value?.[1] ?? '-'
}</span>
<span style="font-size: 12px;">${_unit}</span>
</div>
<div style="display: flex; align-items: center;">
<span>最小值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 5px 0 auto;">${
e[1]?.value?.[1] ?? '-'
}</span>
e[1]?.value?.[1] ?? '-'
}</span>
<span style="font-size: 12px;">${_unit}</span>
</div>
<div style="display: flex; align-items: center;">
<span>最大值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 5px 0 auto;">${
_maxValues[e[2].dataIndex] ?? '-'
}</span>
_maxValues[e[2].dataIndex] ?? '-'
}</span>
<span style="font-size: 12px;">${_unit}</span>
</div>
</div>
</div>`;
},
};
},
};
}
}
}
restOption.dataZoom = [
{
show: true,
bottom: 10,
start: 0,
end: 100,
height: 28,
type: 'inside',
zoomOnMouseWheel: true,
},
{
show: true,
bottom: 10,
start: 0,
end: 100,
height: 28,
type: 'slider',
zoomOnMouseWheel: true,
},
];
xAxis.minInterval = 3600 * 1 * 1000;
return {
yAxis,
grid,
xAxis,
series,
tooltip,
...restOption,
};
restOption.dataZoom = [
{
show: true,
bottom: 10,
start: 0,
end: 100,
height: 28,
type: 'inside',
zoomOnMouseWheel: true,
},
{
show: true,
bottom: 10,
start: 0,
end: 100,
height: 28,
type: 'slider',
zoomOnMouseWheel: true,
},
];
xAxis.minInterval = 3600 * 1 * 1000;
return {
yAxis,
grid,
xAxis,
series,
tooltip,
...restOption,
};
};
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