调整波形图缓存问题

This commit is contained in:
guanj
2026-07-07 13:23:37 +08:00
parent 295cfc6ec1
commit 7ce5600fc9
7 changed files with 1708 additions and 1734 deletions

View File

@@ -1,311 +1,152 @@
// 辅助函数
const getMax = (temp, tempA, tempB, tempC) => {
temp = temp > tempA ? temp : tempA;
temp = temp > tempB ? temp : tempB;
if (tempC !== undefined) {
temp = temp > tempC ? temp : tempC;
import {
buildRmsMinPoint,
buildWaveTitle,
emptyRmsPrimarySeries,
emptyRmsSecondarySeries,
getMax,
getMaxTwo,
getMin,
getMinOpen,
getSampleStep,
getXRange,
isPrimaryValue,
normalizeStats,
parsePhaseTitles,
shouldSamplePoint,
} from "./waveWorkerUtils.js";
const emptyStats = () => ({ max: -Infinity, min: Infinity });
const pushRmsSeries = (series, time, vals, iphasic, usePrimary) => {
if (usePrimary) {
series.rmsFA.push([time, vals[0]]);
if (iphasic >= 2) series.rmsFB.push([time, vals[1]]);
if (iphasic >= 3) series.rmsFC.push([time, vals[2]]);
} else {
series.rmsSA.push([time, vals[0]]);
if (iphasic >= 2) series.rmsSB.push([time, vals[1]]);
if (iphasic >= 3) series.rmsSC.push([time, vals[2]]);
}
return temp;
};
const getMaxTwo = (temp, tempA, tempB) => {
temp = temp > tempA ? temp : tempA;
temp = temp > tempB ? temp : tempB;
return temp;
};
const getMin = (temp, tempA, tempB, tempC) => {
temp = temp < tempA ? temp : tempA;
temp = temp < tempB ? temp : tempB;
if (tempC !== undefined) {
temp = temp < tempC ? temp : tempC;
}
return temp;
};
const getMinOpen = (temp, tempA, tempB) => {
temp = temp < tempA ? temp : tempA;
temp = temp < tempB ? temp : tempB;
return temp;
};
// 数据处理函数
const fliteWaveData = (wp, step, iphasicValue, isOpen) => {
const fliteWaveData = (wp, step, iphasicValue, isOpen, value) => {
const rmsData = wp.listRmsData;
const pt = Number(wp.pt) / 1000;
const ct = Number(wp.ct);
const titleList = wp.waveTitle;
let xishu = pt;
let aTitle = "",
bTitle = "",
cTitle = "",
unit = "电压";
let rmsvFirstX = 0,
rmsvFirstY = 0,
rmsvSecondX = 0,
rmsvSecondY = 0,
firstZhou = "a",
secondeZhou = "a";
let ifmax = 0,
ifmin = 0,
ismax = 0,
ismin = 0,
rfmax = 0,
rfmin = 0,
rsmax = 0,
rsmin = 0;
const { aTitle, bTitle, cTitle, unit } = parsePhaseTitles(wp.waveTitle, iphasicValue, step);
const xishu = unit === "电流" ? ct : pt;
const usePrimary = isPrimaryValue(value);
const shunshiFA = [];
const shunshiFB = [];
const shunshiFC = [];
const shunshiSA = [];
const shunshiSB = [];
const shunshiSC = [];
const rmsFA = [];
const rmsFB = [];
const rmsFC = [];
const rmsSA = [];
const rmsSB = [];
const rmsSC = [];
let rmsvFirstX = 0, rmsvFirstY = Infinity, rmsvSecondX = 0, rmsvSecondY = Infinity;
let firstZhou = "a", secondeZhou = "a";
const RMSF = emptyStats();
const RMSS = emptyStats();
const RMSFWave = emptyRmsPrimarySeries();
const RMSSWave = emptyRmsSecondarySeries();
const activeSeries = usePrimary ? RMSFWave : RMSSWave;
const activeStats = usePrimary ? RMSF : RMSS;
if (titleList[iphasicValue * step + 1]?.substring(0, 1) !== "U") {
xishu = ct;
unit = "电流";
if (!rmsData?.[0] || rmsData[0][iphasicValue * step + 1] === undefined) {
return {
RMSF: normalizeStats(RMSF),
RMSS: normalizeStats(RMSS),
RMSFMinDetail: { rmsvFirstX, rmsvFirstY, firstZhou },
RMSSMinDetail: { rmsvSecondX, rmsvSecondY, secondeZhou },
RMSFWave,
RMSSWave,
title: { aTitle, bTitle, cTitle, unit },
unit,
};
}
for (let i = 1; i <= iphasicValue; i++) {
switch (i) {
case 1:
aTitle = titleList[iphasicValue * step + i]?.substring(1) || "";
break;
case 2:
bTitle = titleList[iphasicValue * step + i]?.substring(1) || "";
break;
case 3:
cTitle = titleList[iphasicValue * step + i]?.substring(1) || "";
break;
}
}
const sampleStep = getSampleStep(rmsData.length);
const base = iphasicValue * step;
if (rmsData[0] && rmsData[0][iphasicValue * step + 1] !== undefined) {
rfmax = rmsData[0][iphasicValue * step + 1] * xishu;
rfmin = rmsData[0][iphasicValue * step + 1] * xishu;
rmsvFirstY = rmsData[0][iphasicValue * step + 1] * xishu;
rmsvFirstX = rmsData[0][0];
rsmax = rmsData[0][iphasicValue * step + 1];
rsmin = rmsData[0][iphasicValue * step + 1];
rmsvSecondY = rmsData[0][iphasicValue * step + 1];
rmsvSecondX = rmsData[0][0];
}
for (let rms = 0; rms < rmsData.length; rms++) {
if (!rmsData[rms] || rmsData[rms][iphasicValue * step + 1] === undefined) {
break;
}
for (let i = 0; i < rmsData.length; i++) {
const row = rmsData[i];
if (!row || row[base + 1] === undefined) break;
const time = row[0];
const scaled = [row[base + 1] * xishu, row[base + 2] * xishu, row[base + 3] * xishu];
const raw = [row[base + 1], row[base + 2], row[base + 3]];
const vals = usePrimary ? scaled : raw;
switch (iphasicValue) {
case 1:
const rmsFirstA = rmsData[rms][iphasicValue * step + 1] * xishu;
rmsFA.push([rmsData[rms][0], rmsFirstA]);
rfmax = rfmax > rmsFirstA ? rfmax : rmsFirstA;
rfmin = rfmin < rmsFirstA ? rfmin : rmsFirstA;
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin;
firstZhou = "a";
rmsvFirstX = rmsData[rms][0];
}
const rmsSecondA = rmsData[rms][iphasicValue * step + 1];
rmsSA.push([rmsData[rms][0], rmsSecondA]);
rsmax = rsmax > rmsSecondA ? rsmax : rmsSecondA;
rsmin = rsmin < rmsSecondA ? rsmin : rmsSecondA;
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin;
secondeZhou = "a";
rmsvSecondX = rmsData[rms][0];
activeStats.max = Math.max(activeStats.max, vals[0]);
activeStats.min = Math.min(activeStats.min, vals[0]);
if (usePrimary && activeStats.min < rmsvFirstY) {
rmsvFirstY = activeStats.min; firstZhou = "a"; rmsvFirstX = time;
} else if (!usePrimary && activeStats.min < rmsvSecondY) {
rmsvSecondY = activeStats.min; secondeZhou = "a"; rmsvSecondX = time;
}
break;
case 2:
const rmsFirstA2 = rmsData[rms][iphasicValue * step + 1] * xishu;
const rmsFirstB2 = rmsData[rms][iphasicValue * step + 2] * xishu;
rmsFA.push([rmsData[rms][0], rmsFirstA2]);
rmsFB.push([rmsData[rms][0], rmsFirstB2]);
rfmax = getMaxTwo(rfmax, rmsFirstA2, rmsFirstB2);
rfmin = getMinOpen(rfmin, rmsFirstA2, rmsFirstB2);
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin;
if (rfmin === rmsFirstA2) {
firstZhou = "a";
} else if (rfmin === rmsFirstB2) {
firstZhou = "b";
}
rmsvFirstX = rmsData[rms][0];
}
const rmsSecondA2 = rmsData[rms][iphasicValue * step + 1];
const rmsSecondB2 = rmsData[rms][iphasicValue * step + 2];
rmsSA.push([rmsData[rms][0], rmsSecondA2]);
rmsSB.push([rmsData[rms][0], rmsSecondB2]);
rsmax = getMaxTwo(rsmax, rmsSecondA2, rmsSecondB2);
rsmin = getMinOpen(rsmin, rmsSecondA2, rmsSecondB2);
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin;
if (rsmin === rmsSecondA2) {
secondeZhou = "a";
} else if (rsmin === rmsSecondB2) {
secondeZhou = "b";
}
rmsvSecondX = rmsData[rms][0];
activeStats.max = getMaxTwo(activeStats.max, vals[0], vals[1]);
activeStats.min = getMinOpen(activeStats.min, vals[0], vals[1]);
if (usePrimary && activeStats.min < rmsvFirstY) {
rmsvFirstY = activeStats.min;
firstZhou = activeStats.min === vals[0] ? "a" : "b";
rmsvFirstX = time;
} else if (!usePrimary && activeStats.min < rmsvSecondY) {
rmsvSecondY = activeStats.min;
secondeZhou = activeStats.min === vals[0] ? "a" : "b";
rmsvSecondX = time;
}
break;
case 3:
const rmsFirstA3 = rmsData[rms][iphasicValue * step + 1] * xishu;
const rmsFirstB3 = rmsData[rms][iphasicValue * step + 2] * xishu;
const rmsFirstC3 = rmsData[rms][iphasicValue * step + 3] * xishu;
rmsFA.push([rmsData[rms][0], rmsFirstA3]);
rmsFB.push([rmsData[rms][0], rmsFirstB3]);
rmsFC.push([rmsData[rms][0], rmsFirstC3]);
rfmax = getMax(rfmax, rmsFirstA3, rmsFirstB3, rmsFirstC3);
rfmin = isOpen
? getMinOpen(rfmin, rmsFirstA3, rmsFirstC3)
: getMin(rfmin, rmsFirstA3, rmsFirstB3, rmsFirstC3);
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin;
if (rfmin === rmsFirstA3) {
firstZhou = "a";
} else if (rfmin === rmsFirstB3) {
firstZhou = "b";
} else {
firstZhou = "c";
}
rmsvFirstX = rmsData[rms][0];
}
const rmsSecondA3 = rmsData[rms][iphasicValue * step + 1];
const rmsSecondB3 = rmsData[rms][iphasicValue * step + 2];
const rmsSecondC3 = rmsData[rms][iphasicValue * step + 3];
rmsSA.push([rmsData[rms][0], rmsSecondA3]);
rmsSB.push([rmsData[rms][0], rmsSecondB3]);
rmsSC.push([rmsData[rms][0], rmsSecondC3]);
rsmax = getMax(rsmax, rmsSecondA3, rmsSecondB3, rmsSecondC3);
rsmin = isOpen
? getMinOpen(rsmin, rmsSecondA3, rmsSecondC3)
: getMin(rsmin, rmsSecondA3, rmsSecondB3, rmsSecondC3);
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin;
if (rsmin === rmsSecondA3) {
secondeZhou = "a";
} else if (rsmin === rmsSecondB3) {
secondeZhou = "b";
} else {
secondeZhou = "c";
}
rmsvSecondX = rmsData[rms][0];
activeStats.max = getMax(activeStats.max, vals[0], vals[1], vals[2]);
activeStats.min = getMin(activeStats.min, vals[0], vals[1], vals[2]);
if (usePrimary && activeStats.min < rmsvFirstY) {
rmsvFirstY = activeStats.min;
firstZhou = activeStats.min === vals[0] ? "a" : activeStats.min === vals[1] ? "b" : "c";
rmsvFirstX = time;
} else if (!usePrimary && activeStats.min < rmsvSecondY) {
rmsvSecondY = activeStats.min;
secondeZhou = activeStats.min === vals[0] ? "a" : activeStats.min === vals[1] ? "b" : "c";
rmsvSecondX = time;
}
break;
}
if (shouldSamplePoint(i, rmsData.length, sampleStep)) {
pushRmsSeries(activeSeries, time, vals, iphasicValue, usePrimary);
}
}
const instantF = { max: ifmax, min: ifmin };
const instantS = { max: ismax, min: ismin };
const RMSF = { max: rfmax, min: rfmin };
const RMSS = { max: rsmax, min: rsmin };
const RMSFMinDetail = { rmsvFirstX, rmsvFirstY, firstZhou };
const RMSSMinDetail = { rmsvSecondX, rmsvSecondY, secondeZhou };
const shunshiF = { shunshiFA, shunshiFB, shunshiFC };
const shunshiS = { shunshiSA, shunshiSB, shunshiSC };
const RMSFWave = { rmsFA, rmsFB, rmsFC };
const RMSSWave = { rmsSA, rmsSB, rmsSC };
const title = { aTitle, bTitle, cTitle, unit };
return {
instantF,
instantS,
RMSF,
RMSS,
RMSFMinDetail,
RMSSMinDetail,
shunshiF,
shunshiS,
RMSF: normalizeStats(RMSF),
RMSS: normalizeStats(RMSS),
RMSFMinDetail: { rmsvFirstX, rmsvFirstY, firstZhou },
RMSSMinDetail: { rmsvSecondX, rmsvSecondY, secondeZhou },
RMSFWave,
RMSSWave,
title,
title: { aTitle, bTitle, cTitle, unit },
unit,
};
};
// 监听消息
self.onmessage = function (e) {
const { wp, isOpen, value, boxoList } = JSON.parse(e.data);
self.addEventListener("message", (e) => {
try {
const { wp, isOpen, boxoList, taskId, value = 2 } = e.data;
const valueType = Number(value) || 2;
const iphasicValue = wp.iphasic || 1;
const picCounts = (wp.waveTitle.length - 1) / iphasicValue;
const waveDatas = [];
for (let i = 0; i < picCounts; i++) {
const data = fliteWaveData(wp, i, iphasicValue, isOpen,boxoList);
waveDatas.push(data);
waveDatas.push(fliteWaveData(wp, i, iphasicValue, isOpen, valueType));
}
// 处理标题
let titles = "";
if (boxoList.systemType == "pms") {
titles =
"变电站名称:" +
boxoList.powerStationName +
" 监测点名称:" +
boxoList.measurementPointName +
" 发生时刻:" +
boxoList.startTime +
" 残余电压:" +
(boxoList.featureAmplitude * 100).toFixed(2) +
"% 持续时间:" +
boxoList.duration +
"s";
} else if (boxoList.systemType == "ZL") {
titles =
" 监测点名称:" +
boxoList.equipmentName +
" 发生时刻:" +
boxoList.startTime +
" 残余电压:" +
boxoList.evtParamVVaDepth +
" 持续时间:" +
boxoList.evtParamTm +
"s";
} else {
titles =
"变电站名称:" +
boxoList.subName +
" 监测点名称:" +
boxoList.lineName +
" 发生时刻:" +
boxoList.startTime +
" 残余电压:" +
(boxoList.featureAmplitude * 100).toFixed(2) +
"% 持续时间:" +
boxoList.duration +
"s";
}
// 发送处理结果回主线程
self.postMessage({
titles: titles,
success: true,
taskId,
titles: buildWaveTitle(boxoList),
waveDatas,
xRange: getXRange(wp.listRmsData),
rmsMinPoint: buildRmsMinPoint(wp, valueType),
time: wp.time,
type: wp.waveType,
severity: wp.yzd,
iphasic: iphasicValue,
});
} catch (error) {
self.postMessage({
success: false,
error: error.message,
});
self.postMessage({ success: false, taskId: e.data?.taskId, error: error.message });
}
};
});

View File

@@ -12,13 +12,25 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
import { ref, computed, onMounted, onBeforeUnmount, watch, toRaw } from 'vue'
import html2canvas from 'html2canvas'
import $ from 'jquery'
import * as echarts from 'echarts'
import url from '@/assets/img/point.png'
import url2 from '@/assets/img/dw.png'
const worker = ref<Worker | null>(null)
import {
bindRmsYAxisOnZoom,
buildRmsWorkerPayload,
buildRmsYAxisScale,
calcVisibleRmsYAxis,
cloneForWorker,
getPhaseSeriesList,
isPrimaryValue,
RMS_ALIGNED_GRID,
} from './waveWorkerUtils.js'
let waveDataWorker: Worker | null = null
let workerTaskId = 0
interface WaveData {
instantF: { max: number; min: number }
instantS: { max: number; min: number }
@@ -101,6 +113,8 @@ const charts = ref({})
const arrpoints = ref([])
const fz = ref<number[]>([])
const titles = ref('')
const xRange = ref({ min: 0, max: 1 })
const rmsMinPoint = ref<{ time: number; display: number } | null>(null)
const zoom = ref(1)
const myChartess = ref<echarts.ECharts | null>(null)
const myChartess1 = ref<echarts.ECharts | null>(null)
@@ -121,55 +135,85 @@ const vh = computed(() => {
const vw = computed(() => '100%')
watch(() => props.value, (newVal) => {
if (newVal == 2) {
initWaves()
} else {
$('#wave1').remove()
initWaves()
const getChartRefs = () => [
myChartess.value,
myChartess1.value,
myChartess2.value,
myChartess3.value,
myChartess4.value,
myChartess5.value,
].filter((c): c is echarts.ECharts => !!c && !c.isDisposed())
const disposeAllCharts = () => {
const charts = getChartRefs()
if (charts.length > 1 && charts[0].group) {
try { echarts.disconnect(charts[0].group) } catch { /* ignore */ }
}
charts.forEach(c => c.dispose())
const rmsEl = document.getElementById('rms')
if (rmsEl) {
const inst = echarts.getInstanceByDom(rmsEl)
if (inst && !inst.isDisposed()) inst.dispose()
}
myChartess.value = null
myChartess1.value = null
myChartess2.value = null
myChartess3.value = null
myChartess4.value = null
myChartess5.value = null
}
const clearExtraWaveDom = () => {
$('#rmsp').nextAll().remove()
}
watch(() => props.value, () => {
workerTaskId++
disposeAllCharts()
clearExtraWaveDom()
query()
})
watch(() => props.wp?.listRmsData, (data) => {
if (data?.length) query()
})
onMounted(() => {
const zoomValue = document.body.style.getPropertyValue('zoom');
zoom.value = 1 / (zoomValue ? parseFloat(zoomValue) : 1);
window.addEventListener('resize', handleResize)
// 初始化 Web Worker
worker.value = new Worker(new URL('./rmsWorker.js', import.meta.url));
worker.value.onmessage = (e) => {
if (e.data.success) {
const data = e.data
titles.value = data.titles
waveDatas.value = data.waveDatas
time.value = data.time
type.value = data.type
severity.value = data.severity
iphasic.value = data.iphasic
// 初始化波形图
initWave(waveDatas.value, time.value, type.value, severity.value, isOpen.value)
} else {
console.error('Worker error:', e.data.error)
loading.value = false
}
}
nextTick(() => {
setTimeout(() => {
query()
}, 500)
})
initWorker()
query()
})
onBeforeUnmount(() => {
if (worker.value) {
worker.value.terminate()
if (waveDataWorker) {
waveDataWorker.terminate()
waveDataWorker = null
}
backbxlb()
window.removeEventListener('resize', handleResize)
})
const initWorker = () => {
if (waveDataWorker) return
waveDataWorker = new Worker(new URL('./rmsWorker.js', import.meta.url), { type: 'module' })
waveDataWorker.onmessage = (e) => {
const data = e.data
if (!data.success || data.taskId !== workerTaskId) return
titles.value = data.titles
iphasic.value = data.iphasic
time.value = data.time
type.value = data.type
severity.value = data.severity
xRange.value = data.xRange || { min: 0, max: 1 }
rmsMinPoint.value = data.rmsMinPoint || null
initWave(data.waveDatas, data.time, data.type, data.severity, isOpen.value)
loading.value = false
}
waveDataWorker.onerror = () => { loading.value = false }
}
const handleResize = () => {
const zoomValue = document.body.style.getPropertyValue('zoom');
zoom.value = 1 / (zoomValue ? parseFloat(zoomValue) : 1);
@@ -192,268 +236,36 @@ const download = () => {
const query = () => {
loading.value = true
if (props.wp) {
// 使用 Worker 处理数据
if (worker.value) {
worker.value.postMessage(JSON.stringify({
wp: props.wp,
isOpen: isOpen.value,
value: props.value,
boxoList: props.boxoList
}))
}
} else {
initWave(null, null, null, null, null)
}
}
const waveData = (
instantF: any,
instantS: any,
RMSF: any,
RMSS: any,
RMSFMinDetail: any,
RMSSMinDetail: any,
shunshiF: any,
shunshiS: any,
RMSFWave: any,
RMSSWave: any,
title: any,
unit: any
): WaveData => {
return {
instantF,
instantS,
RMSF,
RMSS,
RMSFMinDetail,
RMSSMinDetail,
shunshiF,
shunshiS,
RMSFWave,
RMSSWave,
title,
unit
}
initWaves()
}
const initWaves = () => {
if (props.wp) {
iphasic.value = props.wp.iphasic || 1
const picCounts = (props.wp.waveTitle.length - 1) / iphasic.value
waveDatas.value = []
for (let i = 0; i < picCounts; i++) {
const data = fliteWaveData(props.wp, i)
waveDatas.value.push(data)
}
time.value = props.wp.time
type.value = props.wp.waveType
severity.value = props.wp.yzd
if (Number(severity.value) < 0) {
severity.value = '/'
type.value = '/'
}
initWave(waveDatas.value, time.value, type.value, severity.value, isOpen.value)
} else {
if (!props.wp?.listRmsData?.length) {
initWave(null, null, null, null, null)
loading.value = false
return
}
}
const fliteWaveData = (wp: any, step: number): WaveData => {
const rmsData = wp.listRmsData
const pt = Number(wp.pt) / 1000
const ct = Number(wp.ct)
const titleList = wp.waveTitle
let xishu = pt
let aTitle = '', bTitle = '', cTitle = '', unit = '电压'
let rmsvFirstX = 0, rmsvFirstY = 0, rmsvSecondX = 0, rmsvSecondY = 0, firstZhou = 'a', secondeZhou = 'a'
let ifmax = 0, ifmin = 0, ismax = 0, ismin = 0, rfmax = 0, rfmin = 0, rsmax = 0, rsmin = 0
const shunshiFA: number[][] = []
const shunshiFB: number[][] = []
const shunshiFC: number[][] = []
const shunshiSA: number[][] = []
const shunshiSB: number[][] = []
const shunshiSC: number[][] = []
const rmsFA: number[][] = []
const rmsFB: number[][] = []
const rmsFC: number[][] = []
const rmsSA: number[][] = []
const rmsSB: number[][] = []
const rmsSC: number[][] = []
if (titleList[iphasic.value * step + 1]?.substring(0, 1) !== 'U') {
xishu = ct
unit = '电流'
}
for (let i = 1; i <= iphasic.value; i++) {
switch (i) {
case 1:
aTitle = titleList[iphasic.value * step + i]?.substring(1) || ''
break
case 2:
bTitle = titleList[iphasic.value * step + i]?.substring(1) || ''
break
case 3:
cTitle = titleList[iphasic.value * step + i]?.substring(1) || ''
break
}
}
if (rmsData[0][iphasic.value * step + 1] !== undefined) {
rfmax = rmsData[0][iphasic.value * step + 1] * xishu
rfmin = rmsData[0][iphasic.value * step + 1] * xishu
rmsvFirstY = rmsData[0][iphasic.value * step + 1] * xishu
rmsvFirstX = rmsData[0][0]
rsmax = rmsData[0][iphasic.value * step + 1]
rsmin = rmsData[0][iphasic.value * step + 1]
rmsvSecondY = rmsData[0][iphasic.value * step + 1]
rmsvSecondX = rmsData[0][0]
}
for (let rms = 0; rms < rmsData.length; rms++) {
if (rmsData[rms][iphasic.value * step + 1] === undefined) {
break
}
switch (iphasic.value) {
case 1:
const rmsFirstA = rmsData[rms][iphasic.value * step + 1] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA])
rfmax = rfmax > rmsFirstA ? rfmax : rmsFirstA
rfmin = rfmin < rmsFirstA ? rfmin : rmsFirstA
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
firstZhou = 'a'
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA = rmsData[rms][iphasic.value * step + 1]
rmsSA.push([rmsData[rms][0], rmsSecondA])
rsmax = rsmax > rmsSecondA ? rsmax : rmsSecondA
rsmin = rsmin < rmsSecondA ? rsmin : rmsSecondA
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
secondeZhou = 'a'
rmsvSecondX = rmsData[rms][0]
}
break
case 2:
const rmsFirstA2 = rmsData[rms][iphasic.value * step + 1] * xishu
const rmsFirstB2 = rmsData[rms][iphasic.value * step + 2] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA2])
rmsFB.push([rmsData[rms][0], rmsFirstB2])
rfmax = getMaxTwo(rfmax, rmsFirstA2, rmsFirstB2)
rfmin = getMinOpen(rfmin, rmsFirstA2, rmsFirstB2)
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
if (rfmin === rmsFirstA2) {
firstZhou = 'a'
} else if (rfmin === rmsFirstB2) {
firstZhou = 'b'
}
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA2 = rmsData[rms][iphasic.value * step + 1]
const rmsSecondB2 = rmsData[rms][iphasic.value * step + 2]
rmsSA.push([rmsData[rms][0], rmsSecondA2])
rmsSB.push([rmsData[rms][0], rmsSecondB2])
rsmax = getMaxTwo(rsmax, rmsSecondA2, rmsSecondB2)
rsmin = getMinOpen(rsmin, rmsSecondA2, rmsSecondB2)
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
if (rsmin === rmsSecondA2) {
secondeZhou = 'a'
} else if (rsmin === rmsSecondB2) {
secondeZhou = 'b'
}
rmsvSecondX = rmsData[rms][0]
}
break
case 3:
const rmsFirstA3 = rmsData[rms][iphasic.value * step + 1] * xishu
const rmsFirstB3 = rmsData[rms][iphasic.value * step + 2] * xishu
const rmsFirstC3 = rmsData[rms][iphasic.value * step + 3] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA3]);
rmsFB.push([rmsData[rms][0], rmsFirstB3]);
rmsFC.push([rmsData[rms][0], rmsFirstC3]);
rfmax = getMax(rfmax, rmsFirstA3, rmsFirstB3, rmsFirstC3)
rfmin = isOpen.value ? getMinOpen(rfmin, rmsFirstA3, rmsFirstC3) : getMin(rfmin, rmsFirstA3, rmsFirstB3, rmsFirstC3)
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
if (rfmin === rmsFirstA3) {
firstZhou = 'a'
} else if (rfmin === rmsFirstB3) {
firstZhou = 'b'
} else {
firstZhou = 'c'
}
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA3 = rmsData[rms][iphasic.value * step + 1]
const rmsSecondB3 = rmsData[rms][iphasic.value * step + 2]
const rmsSecondC3 = rmsData[rms][iphasic.value * step + 3]
rmsSA.push([rmsData[rms][0], rmsSecondA3])
rmsSB.push([rmsData[rms][0], rmsSecondB3])
rmsSC.push([rmsData[rms][0], rmsSecondC3])
rsmax = getMax(rsmax, rmsSecondA3, rmsSecondB3, rmsSecondC3)
rsmin = isOpen.value ? getMinOpen(rsmin, rmsSecondA3, rmsSecondC3) : getMin(rsmin, rmsSecondA3, rmsSecondB3, rmsSecondC3)
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
if (rsmin === rmsSecondA3) {
secondeZhou = 'a'
} else if (rsmin === rmsSecondB3) {
secondeZhou = 'b'
} else {
secondeZhou = 'c'
}
rmsvSecondX = rmsData[rms][0]
}
break
}
}
const instantF = { max: ifmax, min: ifmin }
const instantS = { max: ismax, min: ismin }
const RMSF = { max: rfmax, min: rfmin }
const RMSS = { max: rsmax, min: rsmin }
const RMSFMinDetail = { rmsvFirstX, rmsvFirstY, firstZhou }
const RMSSMinDetail = { rmsvSecondX, rmsvSecondY, secondeZhou }
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
const RMSFWave = { rmsFA, rmsFB, rmsFC }
const RMSSWave = { rmsSA, rmsSB, rmsSC }
const title = { aTitle, bTitle, cTitle, unit }
return waveData(instantF, instantS, RMSF, RMSS, RMSFMinDetail, RMSSMinDetail, shunshiF, shunshiS, RMSFWave, RMSSWave, title, unit)
loading.value = true
iphasic.value = props.wp.iphasic || 1
initWorker()
const taskId = ++workerTaskId
waveDataWorker!.postMessage({
wp: cloneForWorker(buildRmsWorkerPayload(toRaw(props.wp))),
value: Number(props.value) || 2,
isOpen: isOpen.value,
boxoList: cloneForWorker(toRaw(props.boxoList)),
taskId,
})
}
const initWave = (waveDatas: WaveData[] | null, time: string | null, type: string | null, severity: string | null, isOpen: boolean | null) => {
$('div.bx').remove()
disposeAllCharts()
clearExtraWaveDom()
let picHeight = vh.value
const show = !isOpen
let isvisible = false
let rmscu: number[][] = []
let rmscm: number[][] = []
let titleText = ''
let unit = ''
let a: string | null = null, b: string | null = null, c: string | null = null
@@ -472,16 +284,14 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
switch (iphasic.value) {
case 1:
a = waveDatas[0].title.aTitle
if (props.value === 1) {
if (isPrimaryValue(props.value)) {
rmscu = [[0, waveDatas[0].RMSF.min]]
rmscm = [[0, waveDatas[0].RMSF.max]]
radata = waveDatas[0].RMSFWave.rmsFA
rmsvX = waveDatas[0].RMSFMinDetail.rmsvFirstX
rmsvY = waveDatas[0].RMSFMinDetail.rmsvFirstY
zhou = waveDatas[0].RMSFMinDetail.firstZhou
} else {
rmscu = [[0, waveDatas[0].RMSS.min]]
rmscm = [[0, waveDatas[0].RMSS.max]]
radata = waveDatas[0].RMSSWave.rmsSA
rmsvX = waveDatas[0].RMSSMinDetail.rmsvSecondX
rmsvY = waveDatas[0].RMSSMinDetail.rmsvSecondY
@@ -491,9 +301,8 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
case 2:
a = waveDatas[0].title.aTitle
b = waveDatas[0].title.bTitle
if (props.value === 1) {
if (isPrimaryValue(props.value)) {
rmscu = [[0, waveDatas[0].RMSF.min]]
rmscm = [[0, waveDatas[0].RMSF.max]]
radata = waveDatas[0].RMSFWave.rmsFA
rbdata = waveDatas[0].RMSFWave.rmsFB
rmsvX = waveDatas[0].RMSFMinDetail.rmsvFirstX
@@ -501,7 +310,6 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
zhou = waveDatas[0].RMSFMinDetail.firstZhou
} else {
rmscu = [[0, waveDatas[0].RMSS.min]]
rmscm = [[0, waveDatas[0].RMSS.max]]
radata = waveDatas[0].RMSSWave.rmsSA
rbdata = waveDatas[0].RMSSWave.rmsSB
rmsvX = waveDatas[0].RMSSMinDetail.rmsvSecondX
@@ -513,9 +321,8 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
a = waveDatas[0].title.aTitle
b = waveDatas[0].title.bTitle
c = waveDatas[0].title.cTitle
if (props.value === 1) {
if (isPrimaryValue(props.value)) {
rmscu = [[0, waveDatas[0].RMSF.min]]
rmscm = [[0, waveDatas[0].RMSF.max]]
radata = waveDatas[0].RMSFWave.rmsFA
rbdata = waveDatas[0].RMSFWave.rmsFB
rcdata = waveDatas[0].RMSFWave.rmsFC
@@ -524,7 +331,6 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
zhou = waveDatas[0].RMSFMinDetail.firstZhou
} else {
rmscu = [[0, waveDatas[0].RMSS.min]]
rmscm = [[0, waveDatas[0].RMSS.max]]
radata = waveDatas[0].RMSSWave.rmsSA
rbdata = waveDatas[0].RMSSWave.rmsSB
rcdata = waveDatas[0].RMSSWave.rmsSC
@@ -536,19 +342,10 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
}
if (waveDatas[0].title.unit === '电压') {
if (props.value === 1) {
fz.value = [
props.wp.listRmsMinData[0][0],
Number(((props.wp.listRmsMinData[0][1] * Number(props.wp.pt)) / 1000).toFixed(2))
]
unit = 'kV'
} else {
fz.value = [
props.wp.listRmsMinData[0][0],
props.wp.listRmsMinData[0][1]
]
unit = 'V'
if (rmsMinPoint.value) {
fz.value = [rmsMinPoint.value.time, rmsMinPoint.value.display]
}
unit = isPrimaryValue(props.value) ? 'kV' : 'V'
} else {
unit = 'A'
}
@@ -562,17 +359,25 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
} else {
titleText = `变电站名称:${subName.value} 监测点名称:${lineName.value} 发生时刻:${time} 残余电压:${(Number(eventValue.value) * 1).toFixed(0)}% 持续时间:${persistTime.value}s`
}
const rms = document.getElementById('rmsp')
const phaseSeries = waveDatas?.length
? getPhaseSeriesList(iphasic.value, radata, rbdata, rcdata)
: []
const yBounds = calcVisibleRmsYAxis(phaseSeries)
const yScale = buildRmsYAxisScale(yBounds)
const rms = document.getElementById('rms')
if (!rms) return
rms.style.width = '100%'
rms.style.height = vh.value
const existingChart = echarts.getInstanceByDom(rms)
if (existingChart) existingChart.dispose()
const myChartes = echarts.init(rms)
const echartsColor = { WordColor: "#fff", thread: "#fff", FigureColor: ["#07CCCA ", "#00BFF5", "#FFBF00", "#77DA63", "#D5FF6B", "#Ff6600", "#FF9100", "#5B6E96", "#66FFCC", "#B3B3B3", "#FF00FF", "#CC00FF", "#FF9999"] }
setTimeout(() => {
rms.style.width = '100%'
rms.style.height = vh.value
}, 0)
const option = {
tooltip: {
top: '10px',
@@ -635,8 +440,8 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
xAxis: {
type: 'value',
name: '时间\n(ms)',
min: props.wp?.listRmsData[0][0] || 0,
max: props.wp?.listRmsData[props.wp?.listRmsData.length - 1][0] + 1 || 1,
min: xRange.value.min,
max: xRange.value.max,
boundaryGap: false,
title: {
text: 'ms',
@@ -683,8 +488,9 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
rotation: 0,
y: -10
},
max: rmscm[0]?.[1] * 1.06 || 0,
min: rmscu[0]?.[1] - (rmscu[0]?.[1] * 0.04) || 0,
min: yScale.min,
max: yScale.max,
splitNumber: yScale.splitNumber,
boundaryGap: [0, '100%'],
showLastLabel: true,
opposite: false,
@@ -702,9 +508,7 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
axisLabel: {
fontSize: '0.6rem',
color: props.DColor ? '#fff' : echartsColor.WordColor,
formatter: function (value: number) {
return (value - 0).toFixed(2)
}
formatter: yScale.axisLabel.formatter
},
splitLine: {
lineStyle: {
@@ -714,26 +518,22 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
}
}
},
grid: {
left: '1%',
right: '45px',
bottom: '40px',
top: '70px',
containLabel: true
},
grid: RMS_ALIGNED_GRID,
dataZoom: [
{
type: 'inside',
height: 13,
start: 0,
bottom: '20px',
end: 100
end: 100,
filterMode: 'none'
},
{
start: 0,
height: 13,
bottom: '20px',
end: 100
end: 100,
filterMode: 'none'
}
],
series: [
@@ -742,7 +542,6 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'average',
itemStyle: { color: '#DAA520' },
data: radata
},
@@ -751,7 +550,6 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'average',
itemStyle: { color: '#2E8B57' },
data: rbdata
},
@@ -760,7 +558,6 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'average',
itemStyle: { color: '#A52a2a' },
data: rcdata
},
@@ -795,6 +592,9 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
myChartes.setOption(option)
myChartess.value = myChartes
if (phaseSeries.length) {
bindRmsYAxisOnZoom(myChartes, phaseSeries)
}
setTimeout(() => {
myChartes.resize()
@@ -804,12 +604,12 @@ const initWave = (waveDatas: WaveData[] | null, time: string | null, type: strin
if (waveDatas && waveDatas.length > 1) {
const waveDatasTemp = waveDatas.slice(1)
for (let step = 0; step < waveDatasTemp.length; step++) {
drawPics(waveDatasTemp[step], picHeight, step, show, myChartes, rmscm, rmscu, titleText)
drawPics(waveDatasTemp[step], picHeight, step, show, myChartes, titleText)
}
}
}
const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show: boolean, myChartes1: echarts.ECharts, rmscm: number[][], rmscu: number[][], title: string) => {
const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show: boolean, myChartes1: echarts.ECharts, title: string) => {
step = step + 1
const rmsId = 'rms' + step
let a = '', b = '', c = ''
@@ -831,7 +631,7 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
break
}
if (props.value === 1) {
if (isPrimaryValue(props.value)) {
radata = waveDataTemp.RMSFWave.rmsFA
rbdata = waveDataTemp.RMSFWave.rmsFB
rcdata = waveDataTemp.RMSFWave.rmsFC
@@ -842,11 +642,15 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
}
if (waveDataTemp.title.unit === '电压') {
unit = props.value === 1 ? 'kV' : 'V'
unit = isPrimaryValue(props.value) ? 'kV' : 'V'
} else {
unit = 'A'
}
const phaseSeries = getPhaseSeriesList(iphasic.value, radata, rbdata, rcdata)
const yBounds = calcVisibleRmsYAxis(phaseSeries)
const yScale = buildRmsYAxisScale(yBounds)
let titlename = ''
if (props.boxoList.systemType == 'ZL') {
const str = rmsId.split('s')
@@ -876,6 +680,9 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
const rmsIds = document.getElementById(rmsId)
if (!rmsIds) return
const existingSub = echarts.getInstanceByDom(rmsIds)
if (existingSub && !existingSub.isDisposed()) existingSub.dispose()
const myChartes = echarts.init(rmsIds)
const echartsColor = { WordColor: "#fff", thread: "#fff", FigureColor: ["#07CCCA ", "#00BFF5", "#FFBF00", "#77DA63", "#D5FF6B", "#Ff6600", "#FF9100", "#5B6E96", "#66FFCC", "#B3B3B3", "#FF00FF", "#CC00FF", "#FF9999"] }
@@ -926,8 +733,8 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
xAxis: {
type: 'value',
name: '时间\n(ms)',
min: props.wp.listRmsData[0][0],
max: props.wp.listRmsData[props.wp.listRmsData.length - 1][0] + 1,
min: xRange.value.min,
max: xRange.value.max,
boundaryGap: false,
title: {
text: 'ms',
@@ -974,6 +781,9 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
rotation: 0,
y: -10
},
min: yScale.min,
max: yScale.max,
splitNumber: yScale.splitNumber,
boundaryGap: [0, '100%'],
showLastLabel: true,
opposite: false,
@@ -991,9 +801,7 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
axisLabel: {
fontSize: '0.6rem',
color: props.DColor ? '#fff' : echartsColor.WordColor,
formatter: function (value: number) {
return (value - 0).toFixed(2)
}
formatter: yScale.axisLabel.formatter
},
splitLine: {
lineStyle: {
@@ -1003,26 +811,22 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
}
}
},
grid: {
left: '1%',
right: '45px',
bottom: '40px',
top: '70px',
containLabel: true
},
grid: RMS_ALIGNED_GRID,
dataZoom: [
{
type: 'inside',
height: 13,
start: 0,
bottom: '20px',
end: 100
end: 100,
filterMode: 'none'
},
{
start: 0,
height: 13,
bottom: '20px',
end: 100
end: 100,
filterMode: 'none'
}
],
series: [
@@ -1031,7 +835,6 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'average',
itemStyle: { color: '#DAA520' },
data: radata
},
@@ -1040,7 +843,6 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'average',
itemStyle: { color: '#2E8B57' },
data: rbdata
},
@@ -1049,7 +851,6 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'average',
itemStyle: { color: '#A52a2a' },
data: rcdata
}
@@ -1057,6 +858,9 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
}
myChartes.setOption(option)
if (phaseSeries.length) {
bindRmsYAxisOnZoom(myChartes, phaseSeries)
}
switch (step) {
case 1: myChartess1.value = myChartes; break
@@ -1075,55 +879,11 @@ const drawPics = (waveDataTemp: WaveData, picHeight: string, step: number, show:
}
const backbxlb = () => {
workerTaskId++
waveDatas.value = []
const charts = [myChartess.value, myChartess1.value, myChartess2.value, myChartess3.value, myChartess4.value, myChartess5.value]
charts.forEach(chart => {
if (chart) {
chart.dispose()
}
})
myChartess.value = null
myChartess1.value = null
myChartess2.value = null
myChartess3.value = null
myChartess4.value = null
myChartess5.value = null
// echarts.disconnect(charts.filter(Boolean) as echarts.ECharts[])
charts
.filter(Boolean)
.forEach(chart => {
if (chart && typeof chart.dispose === 'function') {
chart.dispose();
}
});
disposeAllCharts()
clearExtraWaveDom()
}
const getMax = (temp: number, tempA: number, tempB: number, tempC: number): number => {
temp = temp > tempA ? temp : tempA
temp = temp > tempB ? temp : tempB
temp = temp > tempC ? temp : tempC
return temp
}
const getMaxTwo = (temp: number, tempA: number, tempB: number): number => {
temp = temp > tempA ? temp : tempA
temp = temp > tempB ? temp : tempB
return temp
}
const getMin = (temp: number, tempA: number, tempB: number, tempC: number): number => {
temp = temp < tempA ? temp : tempA
temp = temp < tempB ? temp : tempB
temp = temp < tempC ? temp : tempC
return temp
}
const getMinOpen = (temp: number, tempA: number, tempB: number): number => {
temp = temp < tempA ? temp : tempA
temp = temp < tempB ? temp : tempB
return temp
}
defineExpose({ backbxlb, query })
</script>

View File

@@ -1,179 +1,124 @@
// waveData.worker.js
self.addEventListener('message', function(e) {
const { wp, value, iphasic, isOpen, boxoList } = JSON.parse(e.data);
import {
buildWaveTitle,
emptyInstantPrimarySeries,
emptyInstantSecondarySeries,
getSampleStep,
getXRange,
isPrimaryValue,
normalizeStats,
parsePhaseTitles,
shouldSamplePoint,
} from "./waveWorkerUtils.js";
// 处理波形数据的函数
const fliteWaveData = (wp, step) => {
// 将原有的fliteWaveData函数实现复制到这里
const shunData = wp.listWaveData;
const pt = Number(wp.pt) / 1000;
const ct = Number(wp.ct);
const titleList = wp.waveTitle;
let xishu = pt;
let aTitle = '', bTitle = '', cTitle = '', unit = '电压';
let ifmax = 0, ifmin = 0, ismax = 0, ismin = 0;
const emptyStats = () => ({ max: -Infinity, min: Infinity });
const shunshiFA = [];
const shunshiFB = [];
const shunshiFC = [];
const shunshiSA = [];
const shunshiSB = [];
const shunshiSC = [];
const updateStats = (stats, vals, iphasic) => {
const [a, b, c] = vals;
if (iphasic === 1) {
stats.max = Math.max(stats.max, a);
stats.min = Math.min(stats.min, a);
return;
}
if (iphasic === 2) {
stats.max = Math.max(stats.max, a, b);
stats.min = Math.min(stats.min, a, b);
return;
}
stats.max = Math.max(stats.max, a, b, c);
stats.min = Math.min(stats.min, a, b, c);
};
if (shunData.length > 0) {
if (titleList[iphasic * step + 1]?.substring(0, 1) !== 'U') {
xishu = ct;
unit = '电流';
}
for (let i = 1; i <= iphasic; i++) {
switch (i) {
case 1:
aTitle = titleList[iphasic * step + i]?.substring(1) || '';
break;
case 2:
bTitle = titleList[iphasic * step + i]?.substring(1) || '';
break;
case 3:
cTitle = titleList[iphasic * step + i]?.substring(1) || '';
break;
}
}
if (shunData[0][iphasic * step + 1] !== undefined) {
ifmax = shunData[0][iphasic * step + 1] * xishu;
ifmin = shunData[0][iphasic * step + 1] * xishu;
ismax = shunData[0][iphasic * step + 1];
ismin = shunData[0][iphasic * step + 1];
}
for (let shun = 0; shun < shunData.length; shun++) {
if (shunData[shun][iphasic * step + 1] === undefined) {
break;
}
switch (iphasic) {
case 1:
const shunFirstA = shunData[shun][iphasic * step + 1] * xishu;
shunshiFA.push([shunData[shun][0], shunFirstA]);
ifmax = Math.max(ifmax, shunFirstA);
ifmin = Math.min(ifmin, shunFirstA);
const shunSecondA = shunData[shun][iphasic * step + 1];
shunshiSA.push([shunData[shun][0], shunSecondA]);
ismax = Math.max(ismax, shunSecondA);
ismin = Math.min(ismin, shunSecondA);
break;
case 2:
const shunFirstA2 = shunData[shun][iphasic * step + 1] * xishu;
const shunFirstB2 = shunData[shun][iphasic * step + 2] * xishu;
shunshiFA.push([shunData[shun][0], shunFirstA2]);
shunshiFB.push([shunData[shun][0], shunFirstB2]);
ifmax = Math.max(ifmax, shunFirstA2, shunFirstB2);
ifmin = Math.min(ifmin, shunFirstA2, shunFirstB2);
const shunSecondA2 = shunData[shun][iphasic * step + 1];
const shunSecondB2 = shunData[shun][iphasic * step + 2];
shunshiSA.push([shunData[shun][0], shunSecondA2]);
shunshiSB.push([shunData[shun][0], shunSecondB2]);
ismax = Math.max(ismax, shunSecondA2, shunSecondB2);
ismin = Math.min(ismin, shunSecondA2, shunSecondB2);
break;
case 3:
const shunFirstA3 = shunData[shun][iphasic * step + 1] * xishu;
const shunFirstB3 = shunData[shun][iphasic * step + 2] * xishu;
const shunFirstC3 = shunData[shun][iphasic * step + 3] * xishu;
shunshiFA.push([shunData[shun][0], shunFirstA3]);
shunshiFB.push([shunData[shun][0], shunFirstB3]);
shunshiFC.push([shunData[shun][0], shunFirstC3]);
ifmax = Math.max(ifmax, shunFirstA3, shunFirstB3, shunFirstC3);
ifmin = isOpen ? Math.min(ifmin, shunFirstA3, shunFirstC3) : Math.min(ifmin, shunFirstA3, shunFirstB3, shunFirstC3);
const shunSecondA3 = shunData[shun][iphasic * step + 1];
const shunSecondB3 = shunData[shun][iphasic * step + 2];
const shunSecondC3 = shunData[shun][iphasic * step + 3];
shunshiSA.push([shunData[shun][0], shunSecondA3]);
shunshiSB.push([shunData[shun][0], shunSecondB3]);
shunshiSC.push([shunData[shun][0], shunSecondC3]);
ismax = Math.max(ismax, shunSecondA3, shunSecondB3, shunSecondC3);
ismin = isOpen ? Math.min(ismin, shunSecondA3, shunSecondC3) : Math.min(ismin, shunSecondA3, shunSecondB3, shunSecondC3);
break;
}
}
}
const instantF = { max: ifmax, min: ifmin };
const instantS = { max: ismax, min: ismin };
const shunshiF = { shunshiFA, shunshiFB, shunshiFC };
const shunshiS = { shunshiSA, shunshiSB, shunshiSC };
const title = { aTitle, bTitle, cTitle, unit };
return { instantF, instantS, shunshiF, shunshiS, title, unit };
};
// 处理标题
let titles = '';
if (boxoList.systemType == 'pms') {
titles = '变电站名称:' +
boxoList.powerStationName +
' 监测点名称:' +
boxoList.measurementPointName +
' 发生时刻:' +
boxoList.startTime +
' 残余电压:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.duration +
's';
} else if (boxoList.systemType == 'ZL') {
titles = ' 监测点名称:' +
boxoList.equipmentName +
' 发生时刻:' +
boxoList.startTime +
' 残余电压:' +
boxoList.evtParamVVaDepth +
' 持续时间:' +
boxoList.evtParamTm +
's';
const pushSeries = (series, time, vals, iphasic, usePrimary) => {
if (usePrimary) {
series.shunshiFA.push([time, vals[0]]);
if (iphasic >= 2) series.shunshiFB.push([time, vals[1]]);
if (iphasic >= 3) series.shunshiFC.push([time, vals[2]]);
} else {
titles = '变电站名称:' +
boxoList.subName +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 残余电压:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.duration +
's';
series.shunshiSA.push([time, vals[0]]);
if (iphasic >= 2) series.shunshiSB.push([time, vals[1]]);
if (iphasic >= 3) series.shunshiSC.push([time, vals[2]]);
}
};
const fliteWaveData = (wp, step, iphasic, isOpen, value) => {
const shunData = wp.listWaveData;
const pt = Number(wp.pt) / 1000;
const ct = Number(wp.ct);
const { aTitle, bTitle, cTitle, unit } = parsePhaseTitles(wp.waveTitle, iphasic, step);
const xishu = unit === "电流" ? ct : pt;
const usePrimary = isPrimaryValue(value);
const shunshiF = emptyInstantPrimarySeries();
const shunshiS = emptyInstantSecondarySeries();
const instantF = emptyStats();
const instantS = emptyStats();
const activeSeries = usePrimary ? shunshiF : shunshiS;
const activeStats = usePrimary ? instantF : instantS;
if (!shunData?.length || shunData[0][iphasic * step + 1] === undefined) {
return {
instantF: normalizeStats(instantF),
instantS: normalizeStats(instantS),
shunshiF,
shunshiS,
title: { aTitle, bTitle, cTitle, unit },
unit,
};
}
const iphasicValue = wp.iphasic || 1;
const picCounts = (wp.waveTitle.length - 1) / iphasicValue;
const waveDatas = [];
const sampleStep = getSampleStep(shunData.length);
const base = iphasic * step;
for (let i = 0; i < picCounts; i++) {
const data = fliteWaveData(wp, i);
waveDatas.push(data);
for (let i = 0; i < shunData.length; i++) {
const row = shunData[i];
if (row[base + 1] === undefined) break;
const scaledVals = [row[base + 1] * xishu, row[base + 2] * xishu, row[base + 3] * xishu];
const rawVals = [row[base + 1], row[base + 2], row[base + 3]];
const vals = usePrimary ? scaledVals : rawVals;
updateStats(activeStats, vals, iphasic);
if (shouldSamplePoint(i, shunData.length, sampleStep)) {
pushSeries(activeSeries, row[0], vals, iphasic, usePrimary);
}
}
const time = wp.time;
const type = wp.waveType;
let severity = wp.yzd;
return {
instantF: normalizeStats(instantF),
instantS: normalizeStats(instantS),
shunshiF,
shunshiS,
title: { aTitle, bTitle, cTitle, unit },
unit,
};
};
if (severity < 0) {
severity = '/';
type = '/';
self.addEventListener("message", (e) => {
try {
const { wp, isOpen, boxoList, taskId, value = 2 } = e.data;
const valueType = Number(value) || 2;
const iphasicValue = wp.iphasic || 1;
const picCounts = (wp.waveTitle.length - 1) / iphasicValue;
const waveDatas = [];
for (let i = 0; i < picCounts; i++) {
waveDatas.push(fliteWaveData(wp, i, iphasicValue, isOpen, valueType));
}
let severity = wp.yzd;
let type = wp.waveType;
if (severity < 0) {
severity = "/";
type = "/";
}
self.postMessage({
success: true,
taskId,
waveDatas,
xRange: getXRange(wp.listWaveData),
time: wp.time,
type,
severity,
titles: buildWaveTitle(boxoList),
iphasic: iphasicValue,
});
} catch (error) {
self.postMessage({ success: false, taskId: e.data?.taskId, error: error.message });
}
// 将处理结果发送回主线程
self.postMessage({
waveDatas,
time,
type,
severity,
titles,
iphasic: iphasicValue
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,10 @@
<template>
<div v-if="view2" v-loading="loading" element-loading-background="#343849c7">
<el-row v-if="view4">
<div v-if="view2" v-loading="loading" element-loading-background="#343849c7">
<el-row v-if="view4">
<el-col :span="12">
<span style="font-size: 14px; line-height: 30px">值类型选择</span>
<el-select
style="width: 150px"
@change="changeView"
size="small"
v-model="value"
placeholder="请选择值类型"
@@ -15,50 +14,45 @@
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
/>
</el-select>
</el-col>
</el-row>
<div
v-if="view4"
element-loading-background="rgba(122, 122, 122, 0.8)"
style="height: 750px"
>
<el-tabs
class="default-main"
v-model="bxactiveName"
@tab-click="bxhandleClick"
>
<el-tabs class="default-main" v-model="bxactiveName">
<el-tab-pane
label="瞬时波形"
name="ssbx"
class="boxbx pb10"
class="boxbx pb10"
:style="'height:' + bxecharts + ';overflow-y: auto;'"
>
<shushiboxi
v-if="bxactiveName === 'ssbx'"
ref="shushiboxiRef"
v-if="bxactiveName == 'ssbx' && showBoxi"
:value="value"
:parentHeight="parentHeight"
:boxoList="boxoList"
:wp="wp"
></shushiboxi>
/>
</el-tab-pane>
<el-tab-pane
label="RMS波形"
class="boxbx pb10"
name="rmsbx"
class="boxbx pb10"
:style="'height:' + bxecharts + ';overflow-y: auto;'"
>
<rmsboxi
v-if="bxactiveName === 'rmsbx'"
ref="rmsboxiRef"
v-if="bxactiveName == 'rmsbx' && showBoxi"
:value="value"
:parentHeight="parentHeight"
:boxoList="boxoList"
:wp="wp"
></rmsboxi>
/>
</el-tab-pane>
</el-tabs>
</div>
@@ -68,122 +62,130 @@
<script setup lang="ts">
import shushiboxi from "./shushiboxi.vue";
import rmsboxi from "./rmsboxi.vue";
import { ref, reactive } from "vue";
import { ref, shallowRef, markRaw, watch, onBeforeUnmount } from "vue";
import { getTransientAnalyseWave } from "@/api/statistics/index";
const emit = defineEmits(["backbxlb"]);
interface Props {
// boxoList: any
// wp: any,
senior?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
senior: false,
});
const emit = defineEmits(["backbxlb"]);
const parentHeight = ref(0);
const loading = ref(true);
const bxactiveName = ref("ssbx");
const rmsboxiRef = ref();
const value = ref(1);
const options = ref([
{
value: 1,
label: "一次值",
},
{
value: 2,
label: "二次值",
},
{ value: 1, label: "一次值" },
{ value: 2, label: "二次值" },
]);
const shushiboxiRef = ref();
const rmsboxiRef = ref();
const bxecharts = ref("700px");
const view2 = ref(true);
const boxoList: any = ref({});
const wp: any = ref(null);
const showBoxi = ref(true);
const view3 = ref(false);
const view4 = ref(false);
const GJList = ref([]);
const boxoList: any = ref({});
const wp: any = shallowRef(null);
const rmsRawCache = shallowRef<{ listRmsData: any; listRmsMinData: any } | null>(null);
const releaseAllRawWaveData = () => {
if (!wp.value) return;
delete wp.value.listWaveData;
delete wp.value.listRmsData;
delete wp.value.listRmsMinData;
};
const cleanupWaveChildren = () => {
shushiboxiRef.value?.backbxlb?.();
rmsboxiRef.value?.backbxlb?.();
};
const destroyWaveSession = () => {
cleanupWaveChildren();
releaseAllRawWaveData();
rmsRawCache.value = null;
};
const attachRmsRawIfNeeded = () => {
if (!wp.value || !rmsRawCache.value || wp.value.listRmsData) return;
wp.value = markRaw({
...wp.value,
listRmsData: rmsRawCache.value.listRmsData,
listRmsMinData: rmsRawCache.value.listRmsMinData,
});
};
const splitWavePayload = (data: any) => {
const raw = markRaw({ ...data });
if (raw.listRmsData || raw.listRmsMinData) {
rmsRawCache.value = {
listRmsData: raw.listRmsData,
listRmsMinData: raw.listRmsMinData,
};
delete raw.listRmsData;
delete raw.listRmsMinData;
} else {
rmsRawCache.value = null;
}
return raw;
};
watch(bxactiveName, (name) => {
if (name === "rmsbx") attachRmsRawIfNeeded();
}, { flush: "sync" });
const open = async (row: any) => {
console.log("🚀 ~ open ~ row:", row);
destroyWaveSession();
loading.value = true;
await getTransientAnalyseWave({
// id: "151984a0-4a2e-4c46-aece-493e1a2e24c1",
id: row.eventdetail_index,
systemType: 0,
type: 0,
})
.then((res) => {
row.loading = false;
if (res != undefined) {
boxoList.value = {
subName: row.bdname,
lineName: row.pointname,
startTime: row.timeid,
featureAmplitude: row.eventvalue,
duration: row.persisttime,
};
wp.value = res.data;
loading.value = false;
view4.value = true;
}
})
.catch(() => {
loading.value = false;
bxactiveName.value = "ssbx";
try {
const res = await getTransientAnalyseWave({
id: row.eventdetail_index,
systemType: 0,
type: 0,
});
};
const bxhandleClick = (tab: any) => {
// if (shushiboxiRef.value) shushiboxiRef.value.backbxlb();
// if (rmsboxiRef.value) rmsboxiRef.value.backbxlb();
row.loading = false;
// console.log("🚀 ~ open ~ res.data:", res.data)
loading.value = true;
if (tab.name == "ssbx") {
bxactiveName.value = "ssbx";
} else if (tab.name == "rmsbx") {
bxactiveName.value = "rmsbx";
}
setTimeout(() => {
if (res != undefined) {
boxoList.value = {
subName: row.bdname,
lineName: row.pointname,
startTime: row.timeid,
featureAmplitude: row.eventvalue,
duration: row.persisttime,
};
wp.value = splitWavePayload(res.data);
view4.value = true;
}
} catch {
/* ignore */
} finally {
loading.value = false;
}, 0);
// console.log(tab, event);
}
};
const backbxlb = () => {
boxoList.value = null;
wp.value = null;
// if (shushiboxiRef.value) shushiboxiRef.value.backbxlb();
// if (rmsboxiRef.value) rmsboxiRef.value.backbxlb();
const backbxlb = () => {
destroyWaveSession();
boxoList.value = {};
wp.value = null;
view4.value = false;
emit("backbxlb");
};
const setHeight = (h: any, vh: any) => {
if (h != false) {
parentHeight.value = h;
}
const setHeight = (h: any) => {
if (h != false) parentHeight.value = h;
setTimeout(() => {
bxecharts.value = "700px";
}, 100);
};
// 高级分析
const changeView = () => {
// if (shushiboxiRef.value) shushiboxiRef.value.backbxlb();
// if (rmsboxiRef.value) rmsboxiRef.value.backbxlb();
showBoxi.value = false;
setTimeout(() => {
showBoxi.value = true;
}, 0);
};
const gaoBack = () => {
view2.value = true;
view3.value = false;
};
defineExpose({ open, setHeight });
onBeforeUnmount(() => {
destroyWaveSession();
wp.value = null;
boxoList.value = {};
});
defineExpose({ open, setHeight, backbxlb });
</script>
<style lang="scss" scoped>
:deep(.el-tabs__item) {
// color: #c2c2c2;
--el-text-color-primary: #d3d4d6;
}
</style>

View File

@@ -0,0 +1,342 @@
export const MAX_DISPLAY_POINTS = 4000;
export const isPrimaryValue = (value) => Number(value) === 1;
export const getMax = (temp, tempA, tempB, tempC) => {
let result = temp > tempA ? temp : tempA;
result = result > tempB ? result : tempB;
if (tempC !== undefined) result = result > tempC ? result : tempC;
return result;
};
export const getMaxTwo = (temp, tempA, tempB) => {
let result = temp > tempA ? temp : tempA;
return result > tempB ? result : tempB;
};
export const getMin = (temp, tempA, tempB, tempC) => {
let result = temp < tempA ? temp : tempA;
result = result < tempB ? result : tempB;
if (tempC !== undefined) result = result < tempC ? result : tempC;
return result;
};
export const getMinOpen = (temp, tempA, tempB) => {
let result = temp < tempA ? temp : tempA;
return result < tempB ? result : tempB;
};
export const buildWaveTitle = (boxoList) => {
if (boxoList?.systemType === "pms") {
return `变电站名称:${boxoList.powerStationName} 监测点名称:${boxoList.measurementPointName} 发生时刻:${boxoList.startTime} 残余电压:${(boxoList.featureAmplitude * 100).toFixed(2)}% 持续时间:${boxoList.duration}s`;
}
if (boxoList?.systemType === "ZL") {
return ` 监测点名称:${boxoList.equipmentName} 发生时刻:${boxoList.startTime} 残余电压:${boxoList.evtParamVVaDepth} 持续时间:${boxoList.evtParamTm}s`;
}
return `变电站名称:${boxoList.subName} 监测点名称:${boxoList.lineName} 发生时刻:${boxoList.startTime} 残余电压:${(boxoList.featureAmplitude * 100).toFixed(2)}% 持续时间:${boxoList.duration}s`;
};
export const parsePhaseTitles = (titleList, iphasic, step) => {
const base = iphasic * step;
const isCurrent = titleList[base + 1]?.substring(0, 1) !== "U";
const titles = { aTitle: "", bTitle: "", cTitle: "", unit: isCurrent ? "电流" : "电压" };
for (let i = 1; i <= iphasic; i++) {
const title = titleList[base + i]?.substring(1) || "";
if (i === 1) titles.aTitle = title;
else if (i === 2) titles.bTitle = title;
else if (i === 3) titles.cTitle = title;
}
return titles;
};
export const getSampleStep = (total, maxPoints = MAX_DISPLAY_POINTS) => {
if (!total || total <= maxPoints) return 1;
return Math.ceil(total / maxPoints);
};
export const shouldSamplePoint = (index, total, step) =>
index % step === 0 || index === total - 1;
export const cloneForWorker = (data) => JSON.parse(JSON.stringify(data));
export const buildShuWorkerPayload = (wp) => ({
iphasic: wp.iphasic,
pt: wp.pt,
ct: wp.ct,
waveTitle: wp.waveTitle,
listWaveData: wp.listWaveData,
time: wp.time,
waveType: wp.waveType,
yzd: wp.yzd,
});
export const buildRmsWorkerPayload = (wp) => ({
iphasic: wp.iphasic,
pt: wp.pt,
ct: wp.ct,
waveTitle: wp.waveTitle,
listRmsData: wp.listRmsData,
listRmsMinData: wp.listRmsMinData,
time: wp.time,
waveType: wp.waveType,
yzd: wp.yzd,
});
export const getXRange = (list) => {
if (!list?.length) return { min: 0, max: 1 };
return { min: list[0][0], max: list[list.length - 1][0] + 1 };
};
export const normalizeStats = (stats) => {
if (!stats || !isFinite(stats.min) || !isFinite(stats.max)) {
return { min: 0, max: 0 };
}
return stats;
};
/** Y轴最大值×1.2,最小值对称留白使波形居中 */
export const calcYAxisBounds = (dataMin, dataMax) => {
const minVal = Number(dataMin);
const maxVal = Number(dataMax);
if (!isFinite(minVal) || !isFinite(maxVal)) return { min: 0, max: 1 };
if (maxVal === minVal) {
const pad = Math.abs(maxVal) * 0.2 || 1;
return { min: minVal - pad, max: maxVal + pad };
}
const yMax = maxVal * 1.2;
const topPad = yMax - maxVal;
return { min: minVal - topPad, max: yMax };
};
export const calcGlobalInstantRange = (waveDatas, value) => {
const usePrimary = isPrimaryValue(value);
let min = Infinity;
let max = -Infinity;
for (const item of waveDatas || []) {
const stats = normalizeStats(usePrimary ? item.instantF : item.instantS);
min = Math.min(min, stats.min);
max = Math.max(max, stats.max);
}
return calcYAxisBounds(min, max);
};
export const calcGlobalRmsRange = (waveDatas, value) => {
const usePrimary = isPrimaryValue(value);
let min = Infinity;
let max = -Infinity;
for (const item of waveDatas || []) {
const stats = normalizeStats(usePrimary ? item.RMSF : item.RMSS);
min = Math.min(min, stats.min);
max = Math.max(max, stats.max);
}
return calcYAxisBounds(min, max);
};
/** 原瞬时波形 Y 轴公式(多图共用同一范围实现对齐) */
export const calcLegacyInstantYAxis = (dataMin, dataMax) => {
const minNum = Number(Number(dataMin).toFixed(2));
const maxNum = Number(Number(dataMax).toFixed(2));
return {
max: maxNum * 1.1,
min: minNum > 0 ? minNum - minNum * 0.1 : minNum * 1.1,
};
};
/** 从多相序列中取 [xMin, xMax] 内的 y 极值;不传 x 范围则取全量 */
export const calcSeriesDataRange = (seriesList, xMin, xMax) => {
let min = Infinity;
let max = -Infinity;
const hasXBounds = xMin != null && xMax != null && isFinite(xMin) && isFinite(xMax);
for (const series of seriesList || []) {
if (!series?.length) continue;
for (const point of series) {
const x = point[0];
const y = point[1];
if (hasXBounds && (x < xMin || x > xMax)) continue;
if (!isFinite(y)) continue;
min = Math.min(min, y);
max = Math.max(max, y);
}
}
if (!isFinite(min) || !isFinite(max)) return { min: 0, max: 1 };
return { min, max };
};
export const getPhaseSeriesList = (iphasic, adata, bdata, cdata) => {
const list = [adata];
if (iphasic >= 2) list.push(bdata);
if (iphasic >= 3) list.push(cdata);
return list.filter((s) => s?.length);
};
export const getChartXExtent = (chart) => {
const axis = chart.getModel().getComponent("xAxis", 0);
const extent = axis.axis.scale.getExtent();
return { min: extent[0], max: extent[1] };
};
export const calcVisibleInstantYAxis = (seriesList, xMin, xMax) => {
const { min, max } = calcSeriesDataRange(seriesList, xMin, xMax);
return calcLegacyInstantYAxis(min, max);
};
/** 按 Y 轴跨度决定小数位,避免小范围时刻度全显示为 0.0 / 0.1 */
export const calcYAxisLabelPrecision = (min, max) => {
const span = Math.abs(Number(max) - Number(min));
if (!isFinite(span) || span === 0) return 2;
if (span >= 100) return 0;
if (span >= 10) return 1;
if (span >= 1) return 2;
if (span >= 0.1) return 2;
if (span >= 0.01) return 3;
return 4;
};
/** 相邻刻度格式化后相同时隐藏,避免出现 0.0 0.0 0.1 0.1 */
export const createYAxisLabelFormatter = (min, max) => {
let lastLabel = null;
const precision = calcYAxisLabelPrecision(min, max);
return (value) => {
const text = Number(value).toFixed(precision);
if (text === lastLabel) return "";
lastLabel = text;
return text;
};
};
export const buildInstantYAxisScale = (bounds) => ({
min: bounds.min,
max: bounds.max,
splitNumber: 5,
axisLabel: {
formatter: createYAxisLabelFormatter(bounds.min, bounds.max),
},
});
/** dataZoom 时按可见 x 范围重算 Y 轴,使 ABC 相数值与坐标对齐 */
export const bindInstantYAxisOnZoom = (chart, seriesList) => {
const updateYAxis = () => {
if (!chart || chart.isDisposed()) return;
const { min: xMin, max: xMax } = getChartXExtent(chart);
const bounds = calcVisibleInstantYAxis(seriesList, xMin, xMax);
chart.setOption({ yAxis: buildInstantYAxisScale(bounds) });
};
chart.off("dataZoom");
chart.on("dataZoom", updateYAxis);
return updateYAxis;
};
export const calcGlobalLegacyInstantYAxis = (waveDatas, value) => {
const usePrimary = isPrimaryValue(value);
let min = Infinity;
let max = -Infinity;
for (const item of waveDatas || []) {
const stats = normalizeStats(usePrimary ? item.instantF : item.instantS);
min = Math.min(min, stats.min);
max = Math.max(max, stats.max);
}
if (!isFinite(min) || !isFinite(max)) return { min: 0, max: 1 };
return calcLegacyInstantYAxis(min, max);
};
/** 原 RMS 波形 Y 轴公式(多图共用同一范围实现对齐) */
export const calcLegacyRmsYAxis = (dataMin, dataMax) => {
const min = Number(dataMin) || 0;
const max = Number(dataMax) || 0;
return {
max: max * 1.06 || 0,
min: min - min * 0.04 || 0,
};
};
export const calcVisibleRmsYAxis = (seriesList, xMin, xMax) => {
const { min, max } = calcSeriesDataRange(seriesList, xMin, xMax);
return calcLegacyRmsYAxis(min, max);
};
export const buildRmsYAxisScale = (bounds) => ({
min: bounds.min,
max: bounds.max,
splitNumber: 5,
axisLabel: {
formatter: createYAxisLabelFormatter(bounds.min, bounds.max),
},
});
/** dataZoom 时按可见 x 范围重算 RMS Y 轴 */
export const bindRmsYAxisOnZoom = (chart, seriesList) => {
const updateYAxis = () => {
if (!chart || chart.isDisposed()) return;
const { min: xMin, max: xMax } = getChartXExtent(chart);
const bounds = calcVisibleRmsYAxis(seriesList, xMin, xMax);
chart.setOption({ yAxis: buildRmsYAxisScale(bounds) });
};
chart.off("dataZoom");
chart.on("dataZoom", updateYAxis);
return updateYAxis;
};
export const calcGlobalLegacyRmsYAxis = (waveDatas, value) => {
const usePrimary = isPrimaryValue(value);
let min = Infinity;
let max = -Infinity;
for (const item of waveDatas || []) {
const stats = normalizeStats(usePrimary ? item.RMSF : item.RMSS);
min = Math.min(min, stats.min);
max = Math.max(max, stats.max);
}
if (!isFinite(min) || !isFinite(max)) return { min: 0, max: 0 };
return calcLegacyRmsYAxis(min, max);
};
export const WAVE_ALIGNED_GRID = {
left: 56,
right: "2.8%",
bottom: "55px",
top: "70px",
containLabel: false,
};
export const RMS_ALIGNED_GRID = {
left: 56,
right: "45px",
bottom: "55px",
top: "70px",
containLabel: false,
};
export const buildRmsMinPoint = (wp, value) => {
const row = wp.listRmsMinData?.[0];
if (!row) return null;
const raw = row[1];
return {
time: row[0],
display: isPrimaryValue(value)
? Number(((raw * Number(wp.pt)) / 1000).toFixed(2))
: raw,
};
};
export const emptyInstantPrimarySeries = () => ({
shunshiFA: [],
shunshiFB: [],
shunshiFC: [],
});
export const emptyInstantSecondarySeries = () => ({
shunshiSA: [],
shunshiSB: [],
shunshiSC: [],
});
export const emptyRmsPrimarySeries = () => ({
rmsFA: [],
rmsFB: [],
rmsFC: [],
});
export const emptyRmsSecondarySeries = () => ({
rmsSA: [],
rmsSB: [],
rmsSC: [],
});

View File

@@ -134,6 +134,8 @@ const renderChart = (key: any) => {
const outerFontSize = maxChildren > 8 ? 9 : maxChildren > 5 ? 10 : 11;
const outerLabelMaxLen = maxChildren > 8 ? 5 : maxChildren > 5 ? 6 : 8;
const groupScales = getGroupDisplayScales(data.value.innerList || []);
const groupCount = data.value.innerList?.length || 0;
const innerLabelRotate = groupCount <= 1 ? "tangential" : "radial";
myChart.setOption({
title: {
text: "电压暂降用户分类统计(单位:次)",
@@ -172,7 +174,7 @@ const renderChart = (key: any) => {
},
parentId: item.children[0]?.parentId,
label: {
rotate: "radial",
rotate: innerLabelRotate,
color: "#ffffff",
fontSize: 10,
lineHeight: 12,
@@ -236,7 +238,7 @@ const renderChart = (key: any) => {
borderWidth: 2,
},
label: {
rotate: "tangential",
rotate: innerLabelRotate,
},
sort: null,
},