|
|
@@ -45,6 +45,81 @@ const pvPhaseColors = [
|
|
|
const modalChartWidth = 1060
|
|
|
const modalChartHeight = 440
|
|
|
|
|
|
+type RowKind = 'device' | 'site' | 'siteAgg' | 'second' | 'volume'
|
|
|
+type RowMeta = { name: string; kind: RowKind; siteSeq: number }
|
|
|
+
|
|
|
+const SITE_AGG_NAME = '全场点位(归一化)'
|
|
|
+const SITE_AGG_PREFIX = '全场点位·'
|
|
|
+
|
|
|
+// PKS 全场点位按物理分类规范 y 轴:同分类所有子图用同一刻度步长(step),
|
|
|
+// 每个子图范围由各自数据自适应起点/终点;波动过小时用 minSpan 保证最小显示幅度。
|
|
|
+type SiteScaleRule = { unit: string; step: number; minSpan: number }
|
|
|
+const SITE_SCALE_RULES: Record<string, SiteScaleRule> = {
|
|
|
+ 温度: { unit: '℃', step: 5, minSpan: 10 },
|
|
|
+ 压力: { unit: 'MPa', step: 1, minSpan: 2 },
|
|
|
+ 振动: { unit: 'mm/s', step: 0.5, minSpan: 2 },
|
|
|
+ 电流: { unit: 'A', step: 10, minSpan: 20 },
|
|
|
+ 频率: { unit: 'Hz', step: 5, minSpan: 10 },
|
|
|
+ 阀位: { unit: '%', step: 5, minSpan: 10 },
|
|
|
+}
|
|
|
+
|
|
|
+function siteScaleRuleFor(description: string | undefined): SiteScaleRule | null {
|
|
|
+ const text = description ?? ''
|
|
|
+ if (!text) return null
|
|
|
+ if (text.includes('温度') || text.includes('RTD')) return SITE_SCALE_RULES['温度']
|
|
|
+ if (text.includes('压力')) return SITE_SCALE_RULES['压力']
|
|
|
+ if (text.includes('振动')) return SITE_SCALE_RULES['振动']
|
|
|
+ if (text.includes('电流')) return SITE_SCALE_RULES['电流']
|
|
|
+ if (text.includes('频率')) return SITE_SCALE_RULES['频率']
|
|
|
+ if (text.includes('阀位')) return SITE_SCALE_RULES['阀位']
|
|
|
+ return null
|
|
|
+}
|
|
|
+
|
|
|
+function siteAxisRange(rule: SiteScaleRule, values: number[]): { min: number; max: number; interval: number } | null {
|
|
|
+ const finite = values.filter(Number.isFinite)
|
|
|
+ if (!finite.length) return null
|
|
|
+ let min = Math.min(...finite)
|
|
|
+ let max = Math.max(...finite)
|
|
|
+ if (!(max > min)) {
|
|
|
+ min -= rule.minSpan / 2
|
|
|
+ max += rule.minSpan / 2
|
|
|
+ }
|
|
|
+ if (max - min < rule.minSpan) {
|
|
|
+ const center = (max + min) / 2
|
|
|
+ min = center - rule.minSpan / 2
|
|
|
+ max = center + rule.minSpan / 2
|
|
|
+ }
|
|
|
+ min = Math.floor(min / rule.step) * rule.step
|
|
|
+ max = Math.ceil(max / rule.step) * rule.step
|
|
|
+ if (!(max > min)) max = min + rule.step
|
|
|
+ return { min, max, interval: rule.step }
|
|
|
+}
|
|
|
+
|
|
|
+const SPLIT_ROW_HEIGHT = 120
|
|
|
+const SPLIT_ROW_GAP = 14
|
|
|
+const CHART_TOP_INSET = 32
|
|
|
+const CHART_BOTTOM_INSET = 68
|
|
|
+const MERGE_CHART_HEIGHT = 560
|
|
|
+const EMPTY_CHART_HEIGHT = 480
|
|
|
+
|
|
|
+function buildRowMetas(data: WaveWindowResponse): RowMeta[] {
|
|
|
+ const metas: RowMeta[] = data.devicePoints.map((name) => ({ name, kind: 'device' as const, siteSeq: -1 }))
|
|
|
+ const siteMetas: RowMeta[] = []
|
|
|
+ ;(data.siteSeries?.series.filter((series) => series.data.length) ?? []).forEach((series, index) => {
|
|
|
+ siteMetas.push({ name: series.itemName, kind: 'site' as const, siteSeq: index })
|
|
|
+ })
|
|
|
+ metas.push(...siteMetas)
|
|
|
+ if (siteMetas.length > 1) metas.push({ name: SITE_AGG_NAME, kind: 'siteAgg' as const, siteSeq: -1 })
|
|
|
+ if (data.secondSeries.data.length) metas.push({ name: '周期数据', kind: 'second' as const, siteSeq: -1 })
|
|
|
+ if (data.volumeSeries.data.length || data.volumeSeries.info) metas.push({ name: '体积', kind: 'volume' as const, siteSeq: -1 })
|
|
|
+ return metas
|
|
|
+}
|
|
|
+
|
|
|
+function splitTotalHeight(rowCount: number) {
|
|
|
+ if (rowCount <= 0) return EMPTY_CHART_HEIGHT
|
|
|
+ return CHART_TOP_INSET + CHART_BOTTOM_INSET + rowCount * SPLIT_ROW_HEIGHT + (rowCount - 1) * SPLIT_ROW_GAP
|
|
|
+}
|
|
|
+
|
|
|
function niceAxisExtent(values: number[]): [number, number] {
|
|
|
const dataMin = Math.min(...values)
|
|
|
const dataMax = Math.max(...values)
|
|
|
@@ -59,6 +134,14 @@ function niceAxisExtent(values: number[]): [number, number] {
|
|
|
return [Math.floor(min / interval) * interval, Math.ceil(max / interval) * interval]
|
|
|
}
|
|
|
|
|
|
+function rowColor(data: WaveWindowResponse, name: string): string {
|
|
|
+ const meta = buildRowMetas(data).find((item) => item.name === name)
|
|
|
+ if (meta?.kind === 'site') return SITE_POINT_COLORS[meta.siteSeq % SITE_POINT_COLORS.length]
|
|
|
+ const seriesMatch = data.series.find((series) => series.devicePoint === name)
|
|
|
+ if (seriesMatch) return seriesMatch.color
|
|
|
+ return colors[name] ?? '#60717b'
|
|
|
+}
|
|
|
+
|
|
|
function fixedYAxis(devicePoint: string) {
|
|
|
if (props.mode === 'merge') return null
|
|
|
const series = props.data?.series.find((item) => item.devicePoint === devicePoint)
|
|
|
@@ -67,13 +150,15 @@ function fixedYAxis(devicePoint: string) {
|
|
|
}
|
|
|
|
|
|
function splitExtraCount(data: WaveWindowResponse): number {
|
|
|
- let count = 0
|
|
|
- if (data.secondSeries.data.length) count += 1
|
|
|
- if (data.volumeSeries.data.length || data.volumeSeries.info) count += 1
|
|
|
- if (data.siteSeries?.series.some((series) => series.data.length)) count += 1
|
|
|
- return count
|
|
|
+ return Math.max(0, buildRowMetas(data).length - data.devicePoints.length)
|
|
|
}
|
|
|
|
|
|
+const layoutHeightPx = computed(() => {
|
|
|
+ if (props.mode === 'merge') return props.data ? MERGE_CHART_HEIGHT : EMPTY_CHART_HEIGHT
|
|
|
+ if (!props.data) return EMPTY_CHART_HEIGHT
|
|
|
+ return splitTotalHeight(buildRowMetas(props.data).length)
|
|
|
+})
|
|
|
+
|
|
|
const plottedPointCount = computed(() => (
|
|
|
(props.data?.series.reduce((total, series) => total + series.data.length, 0) ?? 0)
|
|
|
+ (props.data?.secondSeries.data.length ?? 0)
|
|
|
@@ -175,7 +260,7 @@ function annotationAreas(annotations: Annotation[]): any[] {
|
|
|
function buildAnnotationOverlaySeries(annotations: Annotation[]): echarts.SeriesOption[] {
|
|
|
const data = props.data
|
|
|
if (!data) return []
|
|
|
- const gridCount = props.mode === 'merge' ? 1 : data.devicePoints.length + splitExtraCount(data)
|
|
|
+ const gridCount = props.mode === 'merge' ? 1 : buildRowMetas(data).length
|
|
|
const areas = annotationAreas(annotations)
|
|
|
return Array.from({ length: gridCount }, (_, index) => ({
|
|
|
id: `annotation-overlay-${index}`,
|
|
|
@@ -262,19 +347,15 @@ function buildOption(zoomMode: 'initial' | 'keep' = 'initial') {
|
|
|
const showVolume = data.volumeSeries.data.length > 0 || data.volumeSeries.info != null
|
|
|
const siteSeries = data.siteSeries?.series.filter((series) => series.data.length) ?? []
|
|
|
const showSite = siteSeries.length > 0
|
|
|
- const extraRows: string[] = []
|
|
|
- if (showSite) extraRows.push('全场点位')
|
|
|
- if (showSecond) extraRows.push('周期数据')
|
|
|
- if (showVolume) extraRows.push('体积')
|
|
|
- const rows = props.mode === 'merge' ? ['合并信号'] : [...devicePoints, ...extraRows]
|
|
|
+ const metas = props.mode === 'merge' ? [] : buildRowMetas(data)
|
|
|
+ const rows = props.mode === 'merge' ? ['合并信号'] : metas.map((meta) => meta.name)
|
|
|
const gridCount = rows.length
|
|
|
- const chartHeight = chartElement.value?.clientHeight || 640
|
|
|
- const topInset = 32
|
|
|
- const bottomInset = 68
|
|
|
- const rowGap = props.mode === 'merge' ? 0 : 14
|
|
|
+ const topInset = CHART_TOP_INSET
|
|
|
+ const bottomInset = CHART_BOTTOM_INSET
|
|
|
+ const rowGap = props.mode === 'merge' ? 0 : SPLIT_ROW_GAP
|
|
|
const rowHeight = props.mode === 'merge'
|
|
|
- ? Math.max(260, chartHeight - topInset - bottomInset)
|
|
|
- : Math.max(76, Math.floor((chartHeight - topInset - bottomInset - rowGap * (gridCount - 1)) / gridCount))
|
|
|
+ ? Math.max(260, MERGE_CHART_HEIGHT - topInset - bottomInset)
|
|
|
+ : SPLIT_ROW_HEIGHT
|
|
|
const grid = Array.from({ length: gridCount }, (_, index) => ({
|
|
|
left: 70,
|
|
|
right: 22,
|
|
|
@@ -302,28 +383,46 @@ function buildOption(zoomMode: 'initial' | 'keep' = 'initial') {
|
|
|
splitLine: { show: false },
|
|
|
}))
|
|
|
const yAxes = rows.map((rowName, index) => {
|
|
|
- const isDevicePoint = (devicePoints as readonly string[]).includes(rowName)
|
|
|
- const seriesColor = isDevicePoint
|
|
|
- ? (data.series.find((series) => series.devicePoint === rowName)?.color ?? '#60717b')
|
|
|
- : (colors[rowName] ?? '#60717b')
|
|
|
+ const meta = metas.find((item) => item.name === rowName)
|
|
|
+ const isDevicePoint = meta?.kind === 'device'
|
|
|
+ const seriesColor = rowColor(data, rowName)
|
|
|
const fixed = isDevicePoint ? fixedYAxis(rowName) : null
|
|
|
const isDisplacement = isDevicePoint
|
|
|
? data.series.find((series) => series.devicePoint === rowName)?.measurementType === '位移'
|
|
|
: false
|
|
|
+ let siteRule: SiteScaleRule | null = null
|
|
|
+ let siteRange: { min: number; max: number; interval: number } | null = null
|
|
|
+ let axisName = rowName
|
|
|
+ if (meta?.kind === 'site') {
|
|
|
+ const rule = siteScaleRuleFor(props.siteDescriptions?.[rowName])
|
|
|
+ if (rule) {
|
|
|
+ siteRule = rule
|
|
|
+ axisName = `${rowName} ${rule.unit}`
|
|
|
+ const siteValues = data.siteSeries?.series.find((series) => series.itemName === rowName)?.data
|
|
|
+ .map((item) => item.value[1]) ?? []
|
|
|
+ siteRange = siteAxisRange(rule, siteValues)
|
|
|
+ }
|
|
|
+ } else if (meta?.kind === 'siteAgg') {
|
|
|
+ siteRange = { min: 0, max: 1, interval: 0.2 }
|
|
|
+ }
|
|
|
return {
|
|
|
type: 'value' as const,
|
|
|
gridIndex: index,
|
|
|
- name: rowName,
|
|
|
+ name: axisName,
|
|
|
nameLocation: 'middle' as const,
|
|
|
- nameGap: 48,
|
|
|
+ nameGap: 52,
|
|
|
nameTextStyle: { color: seriesColor, fontWeight: 600 },
|
|
|
axisLine: { show: true, lineStyle: { color: seriesColor } },
|
|
|
- axisLabel: { color: '#71808a', fontSize: 11 },
|
|
|
+ axisLabel: {
|
|
|
+ color: '#71808a',
|
|
|
+ fontSize: 11,
|
|
|
+ formatter: meta?.kind === 'siteAgg' ? (value: number) => Number(value).toFixed(1) : undefined,
|
|
|
+ },
|
|
|
splitLine: { show: true, lineStyle: { color: '#e7edf0', width: 1 } },
|
|
|
- scale: isDisplacement,
|
|
|
- min: fixed?.min,
|
|
|
- max: fixed?.max,
|
|
|
- interval: fixed?.interval,
|
|
|
+ scale: meta?.kind === 'site' ? !siteRule : isDisplacement,
|
|
|
+ min: siteRange?.min ?? fixed?.min,
|
|
|
+ max: siteRange?.max ?? fixed?.max,
|
|
|
+ interval: siteRange?.interval ?? fixed?.interval,
|
|
|
}
|
|
|
})
|
|
|
const series: echarts.SeriesOption[] = []
|
|
|
@@ -400,10 +499,10 @@ function buildOption(zoomMode: 'initial' | 'keep' = 'initial') {
|
|
|
type: 'line',
|
|
|
xAxisIndex: 0,
|
|
|
yAxisIndex: 0,
|
|
|
- showSymbol: true,
|
|
|
- symbol: 'circle',
|
|
|
- symbolSize: 6,
|
|
|
- lineStyle: { width: 1.5, color, opacity: 0.8 },
|
|
|
+ showSymbol: false,
|
|
|
+ connectNulls: false,
|
|
|
+ sampling: 'lttb' as const,
|
|
|
+ lineStyle: { width: 1.4, color, opacity: 0.8 },
|
|
|
itemStyle: { color },
|
|
|
data: siteItem.data
|
|
|
.filter((item) => Number.isFinite(item.x) && Number.isFinite(item.value[1]))
|
|
|
@@ -412,85 +511,108 @@ function buildOption(zoomMode: 'initial' | 'keep' = 'initial') {
|
|
|
})
|
|
|
}
|
|
|
} else {
|
|
|
- devicePoints.forEach((devicePoint, index) => {
|
|
|
- const source = data.series.find((series) => series.devicePoint === devicePoint)
|
|
|
- const color = source?.color ?? colors[source?.measurementType ?? '加速度']
|
|
|
- series.push({
|
|
|
- name: devicePoint,
|
|
|
- type: 'line',
|
|
|
- z: 10,
|
|
|
- xAxisIndex: index,
|
|
|
- yAxisIndex: index,
|
|
|
- showSymbol: false,
|
|
|
- connectNulls: false,
|
|
|
- sampling: 'lttb' as const,
|
|
|
- lineStyle: { width: 2.5, color, cap: 'round', join: 'round' },
|
|
|
- itemStyle: { color },
|
|
|
- data: source?.data
|
|
|
- .filter((item) => Number.isFinite(item.x) && Number.isFinite(item.rawValue))
|
|
|
- .map((item) => [item.x, item.rawValue] as [number, number]) ?? [],
|
|
|
- markArea: { silent: true, data: periodBackground },
|
|
|
- markLine: index === 0 ? { silent: true, symbol: 'none', data: triggerLines(data.triggerXs) } : undefined,
|
|
|
- })
|
|
|
- })
|
|
|
- if (showSite) {
|
|
|
- const siteIndex = devicePoints.length
|
|
|
- siteSeries.forEach((siteItem, index) => {
|
|
|
- const color = SITE_POINT_COLORS[index % SITE_POINT_COLORS.length]
|
|
|
+ metas.forEach((meta, index) => {
|
|
|
+ if (meta.kind === 'device') {
|
|
|
+ const source = data.series.find((series) => series.devicePoint === meta.name)
|
|
|
+ const color = source?.color ?? colors[source?.measurementType ?? '加速度']
|
|
|
series.push({
|
|
|
- name: siteItem.itemName,
|
|
|
+ name: meta.name,
|
|
|
type: 'line',
|
|
|
z: 10,
|
|
|
- xAxisIndex: siteIndex,
|
|
|
- yAxisIndex: siteIndex,
|
|
|
- showSymbol: true,
|
|
|
- symbol: 'circle',
|
|
|
- symbolSize: 6,
|
|
|
- lineStyle: { width: 1.5, color, opacity: 0.8 },
|
|
|
+ xAxisIndex: index,
|
|
|
+ yAxisIndex: index,
|
|
|
+ showSymbol: false,
|
|
|
+ connectNulls: false,
|
|
|
+ sampling: 'lttb' as const,
|
|
|
+ lineStyle: { width: 2.5, color, cap: 'round', join: 'round' },
|
|
|
+ itemStyle: { color },
|
|
|
+ data: source?.data
|
|
|
+ .filter((item) => Number.isFinite(item.x) && Number.isFinite(item.rawValue))
|
|
|
+ .map((item) => [item.x, item.rawValue] as [number, number]) ?? [],
|
|
|
+ markArea: { silent: true, data: periodBackground },
|
|
|
+ markLine: index === 0 ? { silent: true, symbol: 'none', data: triggerLines(data.triggerXs) } : undefined,
|
|
|
+ })
|
|
|
+ } else if (meta.kind === 'site') {
|
|
|
+ const siteItem = siteSeries.find((series) => series.itemName === meta.name)
|
|
|
+ if (!siteItem) return
|
|
|
+ const color = SITE_POINT_COLORS[meta.siteSeq % SITE_POINT_COLORS.length]
|
|
|
+ series.push({
|
|
|
+ name: meta.name,
|
|
|
+ type: 'line',
|
|
|
+ z: 10,
|
|
|
+ xAxisIndex: index,
|
|
|
+ yAxisIndex: index,
|
|
|
+ showSymbol: false,
|
|
|
+ connectNulls: false,
|
|
|
+ sampling: 'lttb' as const,
|
|
|
+ lineStyle: { width: 1.6, color, opacity: 0.9 },
|
|
|
itemStyle: { color },
|
|
|
data: siteItem.data
|
|
|
.filter((item) => Number.isFinite(item.x) && Number.isFinite(item.value[1]))
|
|
|
.map((item) => [item.x, item.value[1]] as [number, number]),
|
|
|
markArea: { silent: true, data: periodBackground },
|
|
|
})
|
|
|
- })
|
|
|
- }
|
|
|
- if (showSecond) {
|
|
|
- const secondIndex = devicePoints.length + (showSite ? 1 : 0)
|
|
|
- series.push({
|
|
|
- name: '周期数据',
|
|
|
- type: 'line',
|
|
|
- z: 10,
|
|
|
- xAxisIndex: secondIndex,
|
|
|
- yAxisIndex: secondIndex,
|
|
|
- showSymbol: false,
|
|
|
- connectNulls: false,
|
|
|
- lineStyle: { width: 3, color: colors['周期数据'], cap: 'round', join: 'round' },
|
|
|
- areaStyle: { color: 'rgba(245, 108, 108, 0.16)' },
|
|
|
- itemStyle: { color: colors['周期数据'] },
|
|
|
- data: data.secondSeries.data
|
|
|
- .filter((item) => Number.isFinite(item.x) && Number.isFinite(item.rawValue))
|
|
|
- .map((item) => [item.x, item.rawValue] as [number, number]),
|
|
|
- markArea: { silent: true, data: periodBackground },
|
|
|
- })
|
|
|
- }
|
|
|
- if (showVolume) {
|
|
|
- const volumeIndex = devicePoints.length + (showSite ? 1 : 0) + (showSecond ? 1 : 0)
|
|
|
- series.push({
|
|
|
- name: '体积',
|
|
|
- type: 'line',
|
|
|
- z: 10,
|
|
|
- xAxisIndex: volumeIndex,
|
|
|
- yAxisIndex: volumeIndex,
|
|
|
- showSymbol: false,
|
|
|
- lineStyle: { width: 2, color: colors['体积'] },
|
|
|
- itemStyle: { color: colors['体积'] },
|
|
|
- data: data.volumeSeries.data
|
|
|
- .filter((item) => Number.isFinite(item.x) && Number.isFinite(item.volume))
|
|
|
- .map((item) => [item.x, item.volume] as [number, number]),
|
|
|
- markArea: { silent: true, data: periodBackground },
|
|
|
- })
|
|
|
- }
|
|
|
+ } else if (meta.kind === 'siteAgg') {
|
|
|
+ siteSeries.forEach((siteItem) => {
|
|
|
+ const siteValues = siteItem.data
|
|
|
+ .filter((item) => Number.isFinite(item.value[1]))
|
|
|
+ .map((item) => item.value[1])
|
|
|
+ if (!siteValues.length) return
|
|
|
+ const siteMin = Math.min(...siteValues)
|
|
|
+ const siteMax = Math.max(...siteValues)
|
|
|
+ const siteSpan = siteMax - siteMin
|
|
|
+ const siteIndex = siteSeries.findIndex((series) => series.itemName === siteItem.itemName)
|
|
|
+ const color = SITE_POINT_COLORS[siteIndex % SITE_POINT_COLORS.length]
|
|
|
+ series.push({
|
|
|
+ name: `${SITE_AGG_PREFIX}${siteItem.itemName}`,
|
|
|
+ type: 'line',
|
|
|
+ z: 9,
|
|
|
+ xAxisIndex: index,
|
|
|
+ yAxisIndex: index,
|
|
|
+ showSymbol: false,
|
|
|
+ connectNulls: false,
|
|
|
+ sampling: 'lttb' as const,
|
|
|
+ lineStyle: { width: 1.2, color, opacity: 0.85 },
|
|
|
+ itemStyle: { color },
|
|
|
+ data: siteItem.data
|
|
|
+ .filter((item) => Number.isFinite(item.x) && Number.isFinite(item.value[1]))
|
|
|
+ .map((item) => [item.x, siteSpan > 0 ? (item.value[1] - siteMin) / siteSpan : 0.5] as [number, number]),
|
|
|
+ markArea: { silent: true, data: periodBackground },
|
|
|
+ })
|
|
|
+ })
|
|
|
+ } else if (meta.kind === 'second') {
|
|
|
+ series.push({
|
|
|
+ name: '周期数据',
|
|
|
+ type: 'line',
|
|
|
+ z: 10,
|
|
|
+ xAxisIndex: index,
|
|
|
+ yAxisIndex: index,
|
|
|
+ showSymbol: false,
|
|
|
+ connectNulls: false,
|
|
|
+ lineStyle: { width: 3, color: colors['周期数据'], cap: 'round', join: 'round' },
|
|
|
+ areaStyle: { color: 'rgba(245, 108, 108, 0.16)' },
|
|
|
+ itemStyle: { color: colors['周期数据'] },
|
|
|
+ data: data.secondSeries.data
|
|
|
+ .filter((item) => Number.isFinite(item.x) && Number.isFinite(item.rawValue))
|
|
|
+ .map((item) => [item.x, item.rawValue] as [number, number]),
|
|
|
+ markArea: { silent: true, data: periodBackground },
|
|
|
+ })
|
|
|
+ } else if (meta.kind === 'volume') {
|
|
|
+ series.push({
|
|
|
+ name: '体积',
|
|
|
+ type: 'line',
|
|
|
+ z: 10,
|
|
|
+ xAxisIndex: index,
|
|
|
+ yAxisIndex: index,
|
|
|
+ showSymbol: false,
|
|
|
+ lineStyle: { width: 2, color: colors['体积'] },
|
|
|
+ itemStyle: { color: colors['体积'] },
|
|
|
+ data: data.volumeSeries.data
|
|
|
+ .filter((item) => Number.isFinite(item.x) && Number.isFinite(item.volume))
|
|
|
+ .map((item) => [item.x, item.volume] as [number, number]),
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
const zoom = zoomMode === 'keep' ? readCurrentZoom(data) : initialZoom(data)
|
|
|
@@ -516,15 +638,23 @@ function buildOption(zoomMode: 'initial' | 'keep' = 'initial') {
|
|
|
params.forEach((item) => {
|
|
|
const value = item.value?.[1]
|
|
|
if (value !== undefined && value !== null) {
|
|
|
- const seriesName = props.siteDescriptions?.[item.seriesName] || item.seriesName
|
|
|
- lines.push(`<span style="color:${item.color}">●</span> ${seriesName}: ${Number(value).toPrecision(7)}`)
|
|
|
+ const fullName = String(item.seriesName ?? '')
|
|
|
+ const isAgg = fullName.startsWith(SITE_AGG_PREFIX)
|
|
|
+ const base = isAgg ? fullName.slice(SITE_AGG_PREFIX.length) : fullName
|
|
|
+ const seriesName = props.siteDescriptions?.[base] || base
|
|
|
+ lines.push(
|
|
|
+ `<span style="color:${item.color}">●</span> ${seriesName}${isAgg ? ' (归一化)' : ''}: `
|
|
|
+ + `${Number(value).toPrecision(isAgg ? 3 : 7)}`,
|
|
|
+ )
|
|
|
}
|
|
|
})
|
|
|
return lines.join('<br/>')
|
|
|
},
|
|
|
},
|
|
|
legend: {
|
|
|
- data: [...devicePoints, ...extraRows, ...siteSeries.map((series) => series.itemName)],
|
|
|
+ data: props.mode === 'merge'
|
|
|
+ ? [...devicePoints, ...siteSeries.map((series) => series.itemName), ...(showSecond ? ['周期数据'] : []), ...(showVolume ? ['体积'] : [])]
|
|
|
+ : metas.filter((meta) => meta.kind !== 'siteAgg').map((meta) => meta.name),
|
|
|
formatter: (name: string) => props.siteDescriptions?.[name] || name,
|
|
|
top: 0,
|
|
|
left: 70,
|
|
|
@@ -794,7 +924,7 @@ onBeforeUnmount(() => {
|
|
|
<canvas :ref="(el) => setPvCanvas(el, rowIndex)" class="pv-preview-canvas" :aria-label="row.title"></canvas>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div ref="chartElement" class="wave-chart" :class="{ 'is-merge': mode === 'merge' }"></div>
|
|
|
+ <div ref="chartElement" class="wave-chart" :class="{ 'is-merge': mode === 'merge' }" :style="{ height: `${layoutHeightPx}px` }"></div>
|
|
|
<div v-if="annotations?.length" class="annotation-nav">
|
|
|
<div class="annotation-nav-head">
|
|
|
<span class="annotation-nav-title">标注导航</span>
|