|
|
|
|
@ -95,8 +95,11 @@ const parallelChartRef = ref<HTMLElement>()
|
|
|
|
|
|
|
|
|
|
const { getChart } = useChartResize(sankeyChartRef, themeRiverChartRef, treemapChartRef, sunburstChartRef, parallelChartRef)
|
|
|
|
|
|
|
|
|
|
/** 初始化默认时间范围:昨天8:30 ~ 今天8:30 */
|
|
|
|
|
function initTimeRange() {
|
|
|
|
|
const end = new Date(); const start = new Date(end.getTime() - 7 * 24 * 3600 * 1000)
|
|
|
|
|
const now = new Date()
|
|
|
|
|
const end = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 30, 0)
|
|
|
|
|
const start = new Date(end.getTime() - 24 * 3600 * 1000)
|
|
|
|
|
const p = (n: number) => n.toString().padStart(2, '0')
|
|
|
|
|
const fmt = (d: Date) => `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`
|
|
|
|
|
timeRange.value = [fmt(start), fmt(end)]
|
|
|
|
|
@ -245,8 +248,31 @@ function renderParallel(data: TempBoardAdvancedVO[]) {
|
|
|
|
|
if (!chart || !data.length) return
|
|
|
|
|
const dimNames = ['测点', '平均温度', '最高温度', '最低温度', '标准差', '平均延迟(s)']
|
|
|
|
|
const fields = ['avgTemp', 'maxTemp', 'minTemp', 'tempStddev', 'avgDelay'] as const
|
|
|
|
|
// 为每条线生成不同颜色
|
|
|
|
|
const colors = ['#409eff', '#67c23a', '#e6a23c', '#f56c6c', '#9b59b6', '#1abc9c', '#e74c3c', '#2ecc71']
|
|
|
|
|
|
|
|
|
|
// 基于IQR(四分位距)动态计算每根轴的范围,避免异常值导致线条超出可视区域
|
|
|
|
|
function calcAxisRange(field: string): { min: number; max: number } {
|
|
|
|
|
const values = data.map(d => (d as any)[field] as number).filter(v => v != null).sort((a, b) => a - b)
|
|
|
|
|
if (values.length === 0) return { min: 0, max: 100 }
|
|
|
|
|
if (values.length <= 2) {
|
|
|
|
|
// 数据太少时直接用实际范围,加一点余量
|
|
|
|
|
const range = values[values.length - 1] - values[0]
|
|
|
|
|
const pad = Math.max(range * 0.1, 1)
|
|
|
|
|
return { min: Math.floor(values[0] - pad), max: Math.ceil(values[values.length - 1] + pad) }
|
|
|
|
|
}
|
|
|
|
|
const q1 = values[Math.floor(values.length * 0.25)]
|
|
|
|
|
const q3 = values[Math.floor(values.length * 0.75)]
|
|
|
|
|
const iqr = q3 - q1
|
|
|
|
|
// 上下限:Q1 - 1.5*IQR ~ Q3 + 1.5*IQR,并兜底覆盖全部数据
|
|
|
|
|
const lower = Math.min(q1 - 1.5 * iqr, values[0])
|
|
|
|
|
const upper = Math.max(q3 + 1.5 * iqr, values[values.length - 1])
|
|
|
|
|
const pad = Math.max((upper - lower) * 0.05, 0.5)
|
|
|
|
|
return { min: Math.floor(lower - pad), max: Math.ceil(upper + pad) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 为数值维度预计算轴范围
|
|
|
|
|
const axisRanges = fields.map(f => calcAxisRange(f))
|
|
|
|
|
|
|
|
|
|
chart.setOption({
|
|
|
|
|
tooltip: { trigger: 'item' },
|
|
|
|
|
legend: {
|
|
|
|
|
@ -257,7 +283,18 @@ function renderParallel(data: TempBoardAdvancedVO[]) {
|
|
|
|
|
},
|
|
|
|
|
parallelAxis: [
|
|
|
|
|
{ type: 'category', data: data.map(d => d.monitorName || d.monitorId), dim: 0, name: dimNames[0], axisLabel: { rotate: 30, color: '#666' } },
|
|
|
|
|
...fields.map((f, i) => ({ dim: i + 1, name: dimNames[i + 1], axisLabel: { color: '#666' } }))
|
|
|
|
|
...fields.map((f, i) => ({
|
|
|
|
|
type: 'value',
|
|
|
|
|
dim: i + 1,
|
|
|
|
|
name: dimNames[i + 1],
|
|
|
|
|
min: axisRanges[i].min,
|
|
|
|
|
max: axisRanges[i].max,
|
|
|
|
|
nameLocation: 'end',
|
|
|
|
|
nameTextStyle: { color: '#333', fontSize: 12 },
|
|
|
|
|
axisLabel: { color: '#666', fontSize: 11 },
|
|
|
|
|
splitLine: { show: true, lineStyle: { color: '#eee' } },
|
|
|
|
|
axisTick: { show: true }
|
|
|
|
|
}))
|
|
|
|
|
],
|
|
|
|
|
parallel: { left: 100, right: 50, top: 50, bottom: 30 },
|
|
|
|
|
series: data.map((d, idx) => ({
|
|
|
|
|
|