Commit d35c48a5 authored by 陈龙's avatar 陈龙

feat: 新增箱线图、置信区间功能

parent c180e1d5
import React, { memo, useEffect, useMemo, useRef } from 'react';
import { BasicChart } from '@wisdom-components/basicchart';
import React, {memo, useEffect, useMemo, useRef} from 'react';
import {BasicChart} from '@wisdom-components/basicchart';
import PandaEmpty from '@wisdom-components/empty';
import optionGenerator, { alarmMarkLine, minMaxMarkPoint, offlineArea } from './utils';
import { isArray, cloneDeep } from 'lodash';
import optionGenerator, {alarmMarkLine, minMaxMarkPoint, offlineArea} from './utils';
import {isArray, cloneDeep} from 'lodash';
const SimgleChart = memo((props) => {
const {
......@@ -13,6 +13,8 @@ const SimgleChart = memo((props) => {
curveCenter,
showGridLine = false,
deviceAlarmSchemes,
chartType,
justLine
} = props;
const chartRef = useRef();
......@@ -24,6 +26,8 @@ const SimgleChart = memo((props) => {
deviceAlarmSchemes,
showMarkLine: true,
showPoint: true,
chartType,
justLine
};
return optionGenerator(dataSource, null, contrast, contrastOption, smooth, config);
}, [dataSource, smooth, curveCenter]);
......@@ -33,7 +37,7 @@ const SimgleChart = memo((props) => {
const chart = chartRef.current?.getEchartsInstance?.();
function hander(params) {
const { selected } = params;
const {selected} = params;
const count = Object.values(selected || {}).filter((item) => item).length;
const option = cloneDeep(chart.getOption());
const needMarkLine = count === 1;
......@@ -58,6 +62,7 @@ const SimgleChart = memo((props) => {
});
chart.setOption(option, true);
}
if (!chart) return;
chart.on('legendselectchanged', hander);
return () => {
......@@ -95,7 +100,7 @@ const SimgleChart = memo((props) => {
};
let yAxis = axisConfig;
if (isArray(option.yAxis)) {
yAxis = option.yAxis.map((item) => ({ ...axisConfig }));
yAxis = option.yAxis.map((item) => ({...axisConfig}));
}
let xAxis = axisConfig;
chart.setOption({
......@@ -115,9 +120,9 @@ const SimgleChart = memo((props) => {
);
return isEmpty ? (
<PandaEmpty />
<PandaEmpty/>
) : (
<BasicChart ref={chartRef} option={option} notMerge style={{ width: '100%', height: '100%' }} />
<BasicChart ref={chartRef} option={option} notMerge style={{width: '100%', height: '100%'}}/>
);
});
......
......@@ -2,7 +2,7 @@ import React from 'react';
import HistoryView from '../index';
const deviceParams = [
{
/* {
deviceCode: 'EGBF00000146',
sensors: '进水压力,出水瞬时流量,出水累计流量',
deviceType: '二供泵房',
......@@ -13,7 +13,7 @@ const deviceParams = [
sensors: '进水压力,出水瞬时流量,出水累计流量',
deviceType: '二供泵房',
pointAddressID: 4,
},
},*/
{
deviceCode: 'EGBF00000002',
sensors: '进水压力,出水瞬时流量,出水累计流量',
......
......@@ -3,17 +3,20 @@ import HistoryView from '../index';
const deviceParams = [
{
deviceCode: 'EGBF00000146',
sensors: '进水压力,出水瞬时流量,出水累计流量',
deviceCode: 'EGBF00000082',
sensors: '进水压力',
// sensors: '出水瞬时流量',
// sensors: '出水累计流量',
// sensors: '进水压力,出水瞬时流量,出水累计流量',
deviceType: '二供泵房',
pointAddressID: 4,
},
{
deviceCode: 'EGJZ00001113',
/* {
deviceCode: 'EGBF00000083',
sensors: '出水瞬时流量,出水压力,泵1状态',
deviceType: '二供机组',
pointAddressID: 4,
},
},*/
// {
// deviceCode: 'EGJZ00001113',
// sensors: '出水压力',
......@@ -24,7 +27,7 @@ const deviceParams = [
const Demo = () => {
return (
<div style={{ height: 700 }}>
<HistoryView deviceParams={deviceParams} defaultModel="table" />
<HistoryView deviceParams={deviceParams} defaultModel="curve" />
</div>
);
};
......
......@@ -13,7 +13,7 @@ const axisWidth = 40;
* @returns
*/
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;
if (contrast) {
const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, '');
......@@ -31,7 +31,7 @@ const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => {
* @returns 图表系列数据, [[DateTime, value]]
*/
const dataAccessor = (data, contrast, contrastOption) => {
const { dataModel } = data;
const {dataModel} = data;
const formatStr = contrastOption === 'day' ? '2020-01-01 HH:mm:00' : '2020-01-DD HH:mm:00';
return dataModel.map((item) => {
const time = contrast ? moment(item.pt).format(formatStr) : item.pt;
......@@ -46,7 +46,7 @@ const dataAccessor = (data, contrast, contrastOption) => {
* @returns Null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图.
*/
const areaStyleFormatter = (data) => {
const { sensorName } = data;
const {sensorName} = data;
return sensorName && sensorName.indexOf('流量') > -1 ? {} : null;
};
......@@ -57,7 +57,7 @@ const areaStyleFormatter = (data) => {
* @returns
*/
const minMax = (data) => {
const { dataModel } = data;
const {dataModel} = data;
let min = Number.MAX_SAFE_INTEGER;
let max = Number.MIN_SAFE_INTEGER;
dataModel.forEach((item) => {
......@@ -88,7 +88,7 @@ const markLineItem = (name, value, color) => {
export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
// 只有一个数据曲线时显示markline
if (!dataItem || !schemes || dataSource.length !== 1) return {};
const { deviceType, stationCode, sensorName, decimalPoint } = dataItem;
const {deviceType, stationCode, sensorName, decimalPoint} = dataItem;
const curSchemes = schemes.filter(
(item) =>
item.deviceCode === stationCode &&
......@@ -97,7 +97,7 @@ export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
);
const data = [];
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'));
hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16'));
llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000'));
......@@ -128,8 +128,8 @@ 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: '最大: ' });
data.push({type: 'min', name: '最小: '});
data.push({type: 'max', name: '最大: '});
return {
symbolSize: 1,
symbolOffset: [0, '50%'],
......@@ -199,7 +199,7 @@ export const decorateAxisGridLine = (axis, showGrid) => {
*/
export const offlineArea = (dataItem) => {
if (!dataItem) return {};
const { dataModel } = dataItem;
const {dataModel} = dataItem;
let datas = new Array();
let offlineData = [];
let hasOffline = false;
......@@ -247,14 +247,15 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
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 restOption = _.pick(cusOption, ['title', 'legend']);
// 一种指标一个y轴
const yAxisMap = new Map();
dataSource.forEach((item, index) => {
const { sensorName, unit } = item;
const {sensorName, unit} = item;
const key = sensorName;
if (!yAxisMap.has(key)) {
......@@ -300,7 +301,7 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
const axis = yAxisMap.get(key);
decorateAxisGridLine(axis, showGridLine);
});
const yAxis = yAxisMap.size > 0 ? [...yAxisMap.values()] : { type: 'value' };
const yAxis = yAxisMap.size > 0 ? [...yAxisMap.values()] : {type: 'value'};
// 根据y轴个数调整边距
const leftNum = Math.ceil(yAxisMap.size / 2);
......@@ -316,11 +317,10 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
const map = new Map();
let current = -1;
const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name));
return { get };
return {get};
})();
const series = dataSource.map((item, index) => {
const { sensorName, unit } = item;
let series = dataSource.map((item, index) => {
const {sensorName, unit} = item;
const name = nameFormatter(item, contrast, contrastOption, nameWithSensor);
const data = dataAccessor(item, contrast, contrastOption);
const type = 'line';
......@@ -358,7 +358,7 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
.map((item) => item.data?.[item.data.length - 1]?.[0])
.filter((item) => item !== undefined),
);
const xAxis = { type: 'time', min, max };
let xAxis = {type: 'time', min, max};
decorateAxisGridLine(xAxis, showGridLine);
const tooltipTimeFormat = !contrast
......@@ -373,7 +373,65 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
// type: 'cross'
// }
};
// 增加箱线图的逻辑,单曲线才存在
if (!justLine && chartType) {
if (chartType === 'boxChart') {
const otherData = dataSource?.[0]?.dataModel.map(item => {
const {firstPV, lastPV, maxPV, minPV} = item;
return [firstPV, lastPV, minPV, maxPV]
}) || []; //当存在othersData的时候,只是单曲线
series = series.map(item => {
let _item = {...item, symbol: false};
_item.data = _item?.data?.map(d => {
return d[1] || null
}) || [];
return _item;
})
series.push({
type: 'candlestick',
name: '箱线图',
symbol: false,
data: otherData
});
} else {
let _maxData = [];
let _minData = [];
dataSource?.[0]?.dataModel.forEach(item => {
const {firstPV, lastPV, maxPV, minPV} = item;
_maxData.push(maxPV);
_minData.push(minPV);
}); //当存在othersData的时候,只是单曲线
series = series.map(item => {
let _item = {...item, symbol: false};
_item.data = _item?.data?.map(d => {
return d[1] || null
}) || [];
return _item;
});
[[..._minData], [..._maxData]].forEach((item, index) => {
series.push({
name: index === 0 ? '最小值' : '最大值',
type: 'line',
data: item,
lineStyle: {
opacity: 0
},
...(index !== 0 ? {
areaStyle: {
color: '#ccc'
}
} : {}),
stack: 'confidence-band',
symbol: 'none'
});
})
}
xAxis = {type: 'category', data: series[0].data.map(item => moment(item[0]).format('YYYY-MM-DD'))};
tooltip.formatter = (e) => {
console.log(e);
}
}
debugger
return {
yAxis,
grid,
......
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