/** * 异常检测图表视觉语义(前端全场图 + 报告共用) * * 原则: * - 颜色优先表达诊断结论,不用彩虹色表达大量风机编号 * - 异常同时使用红色、菱形和更高层级,避免只依赖颜色 * - 连续变量使用感知均匀、色盲友好的 Viridis 色带 */ export const DIAGNOSTIC_COLORS = { normal: "#2E90FA", anomaly: "#F04438", warning: "#F79009", reference: "#98A2B3", mean: "#7F56D9", blade1: "#2E90FA", blade2: "#12B76A", blade3: "#7F56D9", }; export const DIAGNOSTIC_CATEGORICAL_COLORS = [ "#2E90FA", "#12B76A", "#F79009", "#7F56D9", "#06AED4", "#EE46BC", "#6172F3", "#47CD89", "#FDB022", "#84ADFF", ]; /** 全场总图:正常风机冷色,异常风机红橙暖色;同组内用不同色相区分机组 */ export const FARM_NORMAL_COOL_COLORS = Object.freeze([ "#3B82F6", "#06B6D4", "#0EA5E9", "#2563EB", "#14B8A6", "#6366F1", "#38BDF8", "#0D9488", ]); export const FARM_ANOMALY_WARM_COLORS = Object.freeze([ "#F04438", "#F97316", "#EF4444", "#FB7185", "#EA580C", "#E11D48", "#F59E0B", "#DC2626", ]); export const DIAGNOSTIC_CONTINUOUS_COLORS = [ "#440154", "#3B528B", "#21918C", "#5EC962", "#FDE725", ]; export const DIAGNOSTIC_FARM_STYLES = Object.freeze({ normal: Object.freeze({ pointOpacity: 0.5, lineWidth: 1, lineOpacity: 0.5, z: 1, }), anomaly: Object.freeze({ pointOpacity: 1, lineWidth: 2.4, lineOpacity: 1, z: 20, }), category: Object.freeze({ pointOpacity: 0.88, lineWidth: 1.8, lineOpacity: 1, z: 2, }), }); function seriesText(rowOrLabel) { if (rowOrLabel && typeof rowOrLabel === "object") { return `${rowOrLabel.originalLabel || ""} ${rowOrLabel.label || ""}`; } return String(rowOrLabel || ""); } export function classifyDiagnosticSeries(rowOrLabel) { const text = seriesText(rowOrLabel); if (/桨叶\s*1/.test(text)) return "blade1"; if (/桨叶\s*2/.test(text)) return "blade2"; if (/桨叶\s*3/.test(text)) return "blade3"; if (/异常/.test(text) && !/正常/.test(text)) return "anomaly"; if (/上限|下限|阈值|警戒|频繁/.test(text)) return "warning"; if (/均值|平均|趋势/.test(text)) return "mean"; if (/参考|理论|合同|基准|标准/.test(text) || rowOrLabel?.__shared) { return "reference"; } if (/正常/.test(text)) return "normal"; return "category"; } export function diagnosticSeriesColor(rowOrLabel, index = 0) { const role = classifyDiagnosticSeries(rowOrLabel); if (DIAGNOSTIC_COLORS[role]) return DIAGNOSTIC_COLORS[role]; const safeIndex = Math.abs(Number(index) || 0); return DIAGNOSTIC_CATEGORICAL_COLORS[ safeIndex % DIAGNOSTIC_CATEGORICAL_COLORS.length ]; } function paletteIndexOf(rowOrLabel, index = 0) { const turbineIndex = Number(rowOrLabel?.turbineIndex); if (Number.isFinite(turbineIndex)) return Math.abs(turbineIndex); return Math.abs(Number(index) || 0); } function turbineAnomalyFlag(rowOrLabel) { if (!rowOrLabel || typeof rowOrLabel !== "object") return null; if (typeof rowOrLabel.extra?.anomaly === "boolean") return rowOrLabel.extra.anomaly; if (typeof rowOrLabel.anomaly === "boolean") return rowOrLabel.anomaly; return null; } /** * 全场总图是否按「异常风机」上色。 * 降载图正常/异常是同一台机的点,颜色仍跟风机走,点形再区分状态。 */ export function isFarmAnomalyTurbine(rowOrLabel, templateKey = "") { const flagged = turbineAnomalyFlag(rowOrLabel); if (typeof flagged === "boolean") return flagged; if (templateKey === "ctrl_deload") return false; return classifyDiagnosticSeries(rowOrLabel) === "anomaly"; } export function farmStatusPaletteColor( rowOrLabel, index = 0, templateKey = "", ) { const palette = isFarmAnomalyTurbine(rowOrLabel, templateKey) ? FARM_ANOMALY_WARM_COLORS : FARM_NORMAL_COOL_COLORS; return palette[paletteIndexOf(rowOrLabel, index) % palette.length]; } /** * 全场图颜色语义: * - 正常风机冷色、异常风机红橙暖色,组内再按机组区分; * - 降载图颜色跟风机,点形区分正常/异常点; * - 参考 / 阈值 / 均值保持语义色。 */ export function diagnosticFarmSeriesColor( rowOrLabel, index = 0, templateKey = "", ) { const role = classifyDiagnosticSeries(rowOrLabel); if (role === "reference" || role === "warning" || role === "mean") { return diagnosticSeriesColor(rowOrLabel, index); } return farmStatusPaletteColor(rowOrLabel, index, templateKey); } export function diagnosticFarmSymbolSize( rowOrLabel, pointCount = 0, templateKey = "", ) { const role = classifyDiagnosticSeries(rowOrLabel); if (role === "anomaly") return 14; if (role === "normal") return 7; if (templateKey === "pitch_coord") return pointCount > 800 ? 12 : 14; return pointCount > 500 ? 10 : 12; } export function diagnosticFarmStyle(rowOrLabel) { const role = classifyDiagnosticSeries(rowOrLabel); return ( DIAGNOSTIC_FARM_STYLES[role] || DIAGNOSTIC_FARM_STYLES.category ); } export function diagnosticBladeStyle(rowOrLabel) { const role = classifyDiagnosticSeries(rowOrLabel); if (role === "blade1") { return { symbol: "rect", lineType: "dashed", showSymbol: true }; } if (role === "blade2") { return { symbol: "circle", lineType: "solid", showSymbol: true }; } if (role === "blade3") { return { symbol: "triangle", lineType: "dotted", showSymbol: true }; } return null; } export function diagnosticSeriesSymbol(rowOrLabel, fallback = "circle") { const role = classifyDiagnosticSeries(rowOrLabel); if (role === "anomaly") return "diamond"; if (role === "blade1") return "rect"; if (role === "blade2") return "circle"; if (role === "blade3") return "triangle"; return fallback; } export function diagnosticLineType(rowOrLabel) { const role = classifyDiagnosticSeries(rowOrLabel); if (role === "warning" || role === "reference" || role === "mean") { return "dashed"; } if (role === "blade1") return "dashed"; if (role === "blade3") return "dotted"; return "solid"; }