Commit f94a56bb authored by 李纪文's avatar 李纪文

feat: 组态增加图层设置

parent 451437c1
...@@ -12,6 +12,10 @@ const HistoryTrend = (props) => { ...@@ -12,6 +12,10 @@ const HistoryTrend = (props) => {
const prefixCls = getPrefixCls('history-trend'); const prefixCls = getPrefixCls('history-trend');
const { deviceCode, sensors, deviceType, changeSpin } = props; const { deviceCode, sensors, deviceType, changeSpin } = props;
const chartRef = useRef(null); const chartRef = useRef(null);
const infoRef = useRef({
decimalPoint: 2,
unit: '',
})
const [sensitive, setSensitive] = useState(10); // 敏感度 const [sensitive, setSensitive] = useState(10); // 敏感度
const [timeType, setTimeType] = useState('近7日'); // 时间 const [timeType, setTimeType] = useState('近7日'); // 时间
...@@ -76,6 +80,11 @@ const HistoryTrend = (props) => { ...@@ -76,6 +80,11 @@ const HistoryTrend = (props) => {
let historyData = []; let historyData = [];
results.forEach((result) => { results.forEach((result) => {
const _historyData = result?.data?.[0]?.dataModel || []; const _historyData = result?.data?.[0]?.dataModel || [];
const info = result?.data?.[0] || {};
infoRef.current = {
decimalPoint: info?.decimalPoint || 2,
unit: info?.unit || ''
}
historyData = historyData.concat([..._historyData]); historyData = historyData.concat([..._historyData]);
}); });
console.log(historyData); console.log(historyData);
...@@ -161,11 +170,12 @@ const HistoryTrend = (props) => { ...@@ -161,11 +170,12 @@ const HistoryTrend = (props) => {
let max = Math.max(...pvArr); let max = Math.max(...pvArr);
let min = Math.min(...pvArr); let min = Math.min(...pvArr);
console.log(max, min); console.log(max, min);
const decimalPoint = infoRef.current.decimalPoint || 2;
const data = [ const data = [
(min * (1 - sensitive / 100)).toFixed(2) * 1, (min * (1 - sensitive / 100)).toFixed(decimalPoint) * 1,
(min * (1 + sensitive / 100)).toFixed(2) * 1, (min * (1 + sensitive / 100)).toFixed(decimalPoint) * 1,
(max * (1 - sensitive / 100)).toFixed(2) * 1, (max * (1 - sensitive / 100)).toFixed(decimalPoint) * 1,
(max * (1 + sensitive / 100)).toFixed(2) * 1, (max * (1 + sensitive / 100)).toFixed(decimalPoint) * 1,
]; ];
const color = ['#CB2D2D', '#0087F7']; const color = ['#CB2D2D', '#0087F7'];
const name = ['低低限', '低限', '高限', '高高限']; const name = ['低低限', '低限', '高限', '高高限'];
......
...@@ -80,7 +80,7 @@ const LimitCurve = (props) => { ...@@ -80,7 +80,7 @@ const LimitCurve = (props) => {
<Modal <Modal
closable={false} closable={false}
centered centered
width={width || '1200px'} width={width || '1300px'}
footer={null} footer={null}
open={open} open={open}
visible={open} visible={open}
......
import React, { useContext, useEffect, useRef, useState } from 'react'; import React, { useContext, useEffect, useRef, useState } from 'react';
import { ConfigProvider, Modal, Radio, Slider, InputNumber, Input, Button } from 'antd'; import { ConfigProvider, Modal, Radio, Slider, InputNumber, Input, Button, Checkbox } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import moment from 'moment'; import moment from 'moment';
import { BasicChart } from '@wisdom-components/basicchart'; import { BasicChart } from '@wisdom-components/basicchart';
import { getHistoryInfo } from '../../apis'; import { getHistoryInfo } from '../../apis';
import { std } from 'mathjs'; import { std } from 'mathjs';
import skmeans from 'skmeans'; import skmeans from 'skmeans';
import { outlierArr, timeArr, chartArr, average, markArr } from '../utils'; import { outlierArr, timeArr, chartArr, average, markArr, median } from '../utils';
import './index.less'; import './index.less';
const IntellectDraw = (props) => { const IntellectDraw = (props) => {
...@@ -21,21 +21,11 @@ const IntellectDraw = (props) => { ...@@ -21,21 +21,11 @@ const IntellectDraw = (props) => {
const [sensitive, setSensitive] = useState(10); // 敏感度 const [sensitive, setSensitive] = useState(10); // 敏感度
const [timeCycle, setTimeCycle] = useState(60); const [timeCycle, setTimeCycle] = useState(60);
const [timeDan, setTimeDan] = useState(1); const [timeDan, setTimeDan] = useState(1);
const [foldData, setFoldData] = useState([]);
const [options, setOptions] = useState({}); const [options, setOptions] = useState({});
const chartRef = useRef(null); const chartRef = useRef(null);
// 确定
const onOk = () => {
props.onOk && props.onOk(123);
};
// 取消
const onCancel = () => {
setOpen(false);
props.onCancel && props.onCancel();
};
// 获取历史数据 // 获取历史数据
const getSensorsData = async () => { const getSensorsData = async () => {
changeSpin(true); changeSpin(true);
...@@ -47,6 +37,7 @@ const IntellectDraw = (props) => { ...@@ -47,6 +37,7 @@ const IntellectDraw = (props) => {
dateTo: moment().subtract(1, 'day').format('YYYY-MM-DD 23:59:59'), dateTo: moment().subtract(1, 'day').format('YYYY-MM-DD 23:59:59'),
acrossTables: [{ deviceCode: deviceCode, sensors: sensors, deviceType: deviceType }], acrossTables: [{ deviceCode: deviceCode, sensors: sensors, deviceType: deviceType }],
isBoxPlots: true, isBoxPlots: true,
ignoreOutliers: true,
}; };
const results = await getHistoryInfo(params); const results = await getHistoryInfo(params);
changeSpin(false); changeSpin(false);
...@@ -70,10 +61,76 @@ const IntellectDraw = (props) => { ...@@ -70,10 +61,76 @@ const IntellectDraw = (props) => {
}; };
// 聚集方法 // 聚集方法
const clusteredMothod = () => {}; const clusteredMothod = (clustered, num) => {
console.log(clustered);
let foldLine = [];
const arr = [];
const times = moment().subtract(1, 'day').format('YYYY-MM-DD');
const data = clustered.map((item) => {
return item[1];
});
const medianVal = median([...data]);
console.log(data, medianVal);
if (timeDan === 1) {
return [
[new Date(moment(times + ' 00:00:00')).getTime(), medianVal],
[new Date(moment(times + ' 23:59:59')).getTime(), medianVal],
];
}
data.forEach((item, index) => {
if (
index === 0 ||
(medianVal < item && medianVal > data[index - 1] && index > 0) ||
(medianVal > item && medianVal < data[index - 1] && index > 0)
) {
arr.push([
{
x: clustered[index][0],
y: clustered[index][1],
l: item,
},
]);
} else {
arr[arr.length - 1].push({
x: clustered[index][0],
y: clustered[index][1],
l: item,
});
}
});
console.log(arr);
arr.forEach((list, index) => {
const _list = list.map((item) => {
return item['y'];
});
const _medianVal = median([..._list]);
if (index === 0) {
foldLine = foldLine.concat([
[new Date(moment(times + ' 00:00:00')).getTime(), _medianVal],
[list[list.length - 1].x, _medianVal],
]);
} else if (index === arr.length - 1) {
foldLine = foldLine.concat([
[arr[index - 1].at(-1).x, _medianVal],
[new Date(moment(times + ' 23:59:59')).getTime(), _medianVal],
]);
} else {
foldLine = foldLine.concat([
[arr[index - 1].at(-1).x, _medianVal],
[list[list.length - 1].x, _medianVal],
]);
}
});
console.log(foldLine);
if (arr.length === timeDan || arr.length === num) {
return foldLine;
} else {
return clusteredMothod(foldLine, arr.length);
}
};
// 渲染图表 // 渲染图表
const renderChart = (_chartData) => { const renderChart = (_chartData, _clustered) => {
const chartDatas = _chartData.map((item) => { const chartDatas = _chartData.map((item) => {
return [new Date(item.time).getTime(), item.pv]; return [new Date(item.time).getTime(), item.pv];
}); });
...@@ -83,6 +140,8 @@ const IntellectDraw = (props) => { ...@@ -83,6 +140,8 @@ const IntellectDraw = (props) => {
return a[0] - b[0]; return a[0] - b[0];
}); });
console.log(_centroids); console.log(_centroids);
const foldLine = clusteredMothod(_centroids, 0);
console.log(foldLine);
const option = { const option = {
xAxis: { xAxis: {
type: 'time', type: 'time',
...@@ -122,22 +181,64 @@ const IntellectDraw = (props) => { ...@@ -122,22 +181,64 @@ const IntellectDraw = (props) => {
}, },
{ {
type: 'line', type: 'line',
name: sensors, name: '趋势',
sampling: 'average', sampling: 'average',
large: true, large: true,
data: _centroids.map((item) => { data: _centroids.map((item) => {
return [Math.floor(item[0]), item[1]]; return [Math.floor(item[0]), item[1]];
}), }),
}, },
{
type: 'line',
name: '限值',
data: foldLine.map((item) => {
return [Math.floor(item[0]), item[1]];
}),
},
], ],
}; };
setOptions(option); setOptions(option);
setFoldData(foldDataMethod(foldLine));
};
// 限值数据处理
const foldDataMethod = (data) => {
let _data = [];
data.forEach((item, index) => {
if (index % 2 === 0) {
_data = _data.concat([[item]]);
} else {
_data[Math.floor(index / 2)].push([...item]);
}
});
console.log(_data);
return _data.map((list) => {
return {
start: moment(list[0][0]).format('HH:mm'),
end: moment(list[1][0]).format('HH:mm'),
value: list[0][1],
wave: 10,
};
});
};
const onCheckChange = (checkedValues) => {
console.log(checkedValues);
}; };
const proposeRender = () => { const proposeRender = () => {
return ( return (
<> <div className={classNames(`${prefixCls}-propose-box`)}>
<div className={classNames(`${prefixCls}-propose-list`)}> <Checkbox.Group onChange={onCheckChange}>
{foldData.map((list, index) => {
return (
<div className={classNames(`${prefixCls}-propose-list`)} key={index}>
<div className={classNames(`${prefixCls}-propose-select`)}>
<Checkbox value={index}>
{list.start}-{list.end}
</Checkbox>
</div>
<div className={classNames(`${prefixCls}-propose-value`)}> <div className={classNames(`${prefixCls}-propose-value`)}>
<div className={classNames(`${prefixCls}-value-list`)}> <div className={classNames(`${prefixCls}-value-list`)}>
<Input <Input
...@@ -202,7 +303,10 @@ const IntellectDraw = (props) => { ...@@ -202,7 +303,10 @@ const IntellectDraw = (props) => {
/> />
</div> </div>
</div> </div>
</> );
})}
</Checkbox.Group>
</div>
); );
}; };
...@@ -233,8 +337,7 @@ const IntellectDraw = (props) => { ...@@ -233,8 +337,7 @@ const IntellectDraw = (props) => {
).getTime(); ).getTime();
return time && time >= min && max >= time; return time && time >= min && max >= time;
}); });
const clusteredArr = []; let dataArr = [];
const dataArr = [];
const pvArr = data.map((item) => { const pvArr = data.map((item) => {
return item.pv; return item.pv;
}); });
...@@ -246,16 +349,13 @@ const IntellectDraw = (props) => { ...@@ -246,16 +349,13 @@ const IntellectDraw = (props) => {
}; };
data.forEach((item) => { data.forEach((item) => {
if (item.pv >= range.min && item.pv <= range.max) dataArr.push(item); if (item.pv >= range.min && item.pv <= range.max) dataArr.push(item);
clusteredArr.push([new Date(item.time).getTime(), item.pv]);
}); });
const clustered = clusteredArr.length ? skmeans(clusteredArr, 1) : {}; if (!outlier) dataArr = [].concat([...data]);
const { centroids = [] } = clustered;
_chartData.push(...dataArr); _chartData.push(...dataArr);
_clustered.push(...centroids);
} }
renderChart(_chartData, _clustered); renderChart(_chartData, _clustered);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [sensorData, outlier]); }, [sensorData, outlier, timeDan]);
useEffect(() => { useEffect(() => {
setOpen(props.open); setOpen(props.open);
......
...@@ -37,9 +37,25 @@ ...@@ -37,9 +37,25 @@
display: flex; display: flex;
} }
&-propose-box {
display: flex;
flex-direction: column;
}
&-propose-list { &-propose-list {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 5px;
&:last-of-type {
margin-bottom: 0px;
}
}
&-propose-select {
margin: 10px;
display: flex;
align-items: center;
} }
&-value-list { &-value-list {
......
...@@ -54,3 +54,18 @@ export const chartArr = [ ...@@ -54,3 +54,18 @@ export const chartArr = [
export const average = (arr) => { export const average = (arr) => {
return arr.reduce((acc, cur) => acc + cur, 0) / arr.length; return arr.reduce((acc, cur) => acc + cur, 0) / arr.length;
}; };
// 中位数方法
export const median = (data) => {
if (data.length === 0) return 0;
data.sort((a, b) => {
return a - b;
});
const half = Math.floor(data.length / 2);
if (data.length % 2) return data[half];
return (data[half - 1] + data[half]) / 2;
};
...@@ -2373,6 +2373,7 @@ const ConfigurationView = (props) => { ...@@ -2373,6 +2373,7 @@ const ConfigurationView = (props) => {
relinkableTo: true, relinkableTo: true,
zOrder: 1, zOrder: 1,
}, },
new go.Binding('layerName', 'layerName').makeTwoWay(),
new go.Binding('fromSpot', 'fromPort', (d) => { new go.Binding('fromSpot', 'fromPort', (d) => {
return spotConverter(d); return spotConverter(d);
}), }),
...@@ -2422,6 +2423,7 @@ const ConfigurationView = (props) => { ...@@ -2422,6 +2423,7 @@ const ConfigurationView = (props) => {
relinkableTo: true, relinkableTo: true,
zOrder: 1, zOrder: 1,
}, },
new go.Binding('layerName', 'layerName').makeTwoWay(),
new go.Binding('fromSpot', 'fromPort', function (d) { new go.Binding('fromSpot', 'fromPort', function (d) {
return spotConverter(d); return spotConverter(d);
}), }),
......
...@@ -3017,6 +3017,7 @@ const ConfigurationView = (props) => { ...@@ -3017,6 +3017,7 @@ const ConfigurationView = (props) => {
relinkableTo: true, relinkableTo: true,
zOrder: 1, zOrder: 1,
}, },
new go.Binding('layerName', 'layerName').makeTwoWay(),
new go.Binding('fromSpot', 'fromPort', (d) => { new go.Binding('fromSpot', 'fromPort', (d) => {
return spotConverter(d); return spotConverter(d);
}), }),
...@@ -3066,6 +3067,7 @@ const ConfigurationView = (props) => { ...@@ -3066,6 +3067,7 @@ const ConfigurationView = (props) => {
relinkableTo: true, relinkableTo: true,
zOrder: 1, zOrder: 1,
}, },
new go.Binding('layerName', 'layerName').makeTwoWay(),
new go.Binding('fromSpot', 'fromPort', function (d) { new go.Binding('fromSpot', 'fromPort', function (d) {
return spotConverter(d); return spotConverter(d);
}), }),
......
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