|
@@ -1,4 +1,5 @@
|
|
|
import { readCssVar } from "@/utils/chartTheme";
|
|
import { readCssVar } from "@/utils/chartTheme";
|
|
|
|
|
+import { formatWakeMetric, formatWakePercent } from "./wrwTableUtils";
|
|
|
|
|
|
|
|
function getWakeChartTheme() {
|
|
function getWakeChartTheme() {
|
|
|
return {
|
|
return {
|
|
@@ -9,96 +10,268 @@ function getWakeChartTheme() {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const scatterData = [
|
|
|
|
|
- { name: "L9Xcm4u0", value: [333330, 4173350, 7.8] },
|
|
|
|
|
- { name: "o23d6LBB", value: [333320, 4173300, 7.5] },
|
|
|
|
|
- { name: "0DdPWnck", value: [333310, 4173380, 4.8] },
|
|
|
|
|
- { name: "CZbp7no4", value: [333290, 4174350, 8.1] },
|
|
|
|
|
- { name: "4dCWnzLK", value: [333300, 4174380, 2.5] },
|
|
|
|
|
- { name: "3dORuyAV", value: [333240, 4173720, 3.4] },
|
|
|
|
|
- { name: "SPlyMKa9", value: [333270, 4173320, 4.5] },
|
|
|
|
|
- { name: "86n2qgiM", value: [333230, 4172950, 4.5] },
|
|
|
|
|
- { name: "BCKL9lkw", value: [333420, 4173200, 34.6] },
|
|
|
|
|
- { name: "qAqnO0YH", value: [333280, 4172580, 0.2] },
|
|
|
|
|
- { name: "I7EJ4nPt", value: [333360, 4173450, 59.6] },
|
|
|
|
|
- { name: "RQov6gm3", value: [333315, 4172900, 4.1] },
|
|
|
|
|
- { name: "7xKAWgZW", value: [333410, 4172980, 84.7] },
|
|
|
|
|
- { name: "olFRqfSf", value: [333400, 4173380, 12.8] },
|
|
|
|
|
- { name: "NSfopOW3", value: [333370, 4173750, 2.4] },
|
|
|
|
|
- { name: "3jyH154U", value: [333270, 4172520, 0.4] },
|
|
|
|
|
-];
|
|
|
|
|
|
|
+const SCATTER1_X_AXIS_NAME = "东西方向坐标(千米)";
|
|
|
|
|
+const SCATTER1_Y_AXIS_NAME = "南北方向坐标(千米)";
|
|
|
|
|
|
|
|
-const scatter2Data = [
|
|
|
|
|
- { name: "L9Xcm4u0", value: [7.8, 92], itemStyle: { color: "#C0C0C0" } },
|
|
|
|
|
- { name: "o23d6LBB", value: [7.5, 78], itemStyle: { color: "#D4C4B0" } },
|
|
|
|
|
- { name: "0DdPWnck", value: [4.8, 85], itemStyle: { color: "#B0B0B0" } },
|
|
|
|
|
- { name: "CZbp7no4", value: [8.1, 88], itemStyle: { color: "#A0A0A0" } },
|
|
|
|
|
- { name: "4dCWnzLK", value: [2.5, 79], itemStyle: { color: "#C8C8C8" } },
|
|
|
|
|
- { name: "3dORuyAV", value: [3.4, 95], itemStyle: { color: "#4CAF50" } },
|
|
|
|
|
- { name: "SPlyMKa9", value: [4.5, 79], itemStyle: { color: "#C0C0C0" } },
|
|
|
|
|
- { name: "86n2qgiM", value: [4.5, 91], itemStyle: { color: "#66BB6A" } },
|
|
|
|
|
- { name: "BCKL9lkw", value: [34.6, 78], itemStyle: { color: "#D4C4B0" } },
|
|
|
|
|
- { name: "qAqnO0YH", value: [0.2, 93], itemStyle: { color: "#4CAF50" } },
|
|
|
|
|
- { name: "I7EJ4nPt", value: [59.6, 82], itemStyle: { color: "#CD853F" } },
|
|
|
|
|
- { name: "RQov6gm3", value: [4.1, 94], itemStyle: { color: "#4CAF50" } },
|
|
|
|
|
- { name: "7xKAWgZW", value: [84.7, 87], itemStyle: { color: "#E85D5D" } },
|
|
|
|
|
- { name: "olFRqfSf", value: [12.8, 88], itemStyle: { color: "#66BB6A" } },
|
|
|
|
|
- { name: "NSfopOW3", value: [2.4, 92], itemStyle: { color: "#4CAF50" } },
|
|
|
|
|
- { name: "3jyH154U", value: [0.4, 67], itemStyle: { color: "#E85D5D" } },
|
|
|
|
|
-];
|
|
|
|
|
|
|
+function formatScatter1AxisValue(value) {
|
|
|
|
|
+ return formatWakeMetric(Number(value) / 1000);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function mapLayoutScatterPoints(points) {
|
|
|
|
|
+ if (!Array.isArray(points) || !points.length) return [];
|
|
|
|
|
+ return points.map((item) => ({
|
|
|
|
|
+ name: item.engineId || item.name || "",
|
|
|
|
|
+ value: [
|
|
|
|
|
+ item.east ?? item.value?.[0] ?? 0,
|
|
|
|
|
+ item.north ?? item.value?.[1] ?? 0,
|
|
|
|
|
+ item.lossPercent ?? item.velocityDeficit ?? item.value?.[2] ?? 0,
|
|
|
|
|
+ ],
|
|
|
|
|
+ }));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function mapWakeLossConfidentPoints(points) {
|
|
|
|
|
+ if (!Array.isArray(points) || !points.length) return [];
|
|
|
|
|
+ return points.map((item) => {
|
|
|
|
|
+ const confidenceRaw =
|
|
|
|
|
+ item.confidencePercent ?? item.confidentLevel ?? item.value?.[1] ?? 0;
|
|
|
|
|
+ const confidenceNum = Number(confidenceRaw);
|
|
|
|
|
+ const confidencePercent =
|
|
|
|
|
+ confidenceNum <= 1 ? confidenceNum * 100 : confidenceNum;
|
|
|
|
|
+ const loss =
|
|
|
|
|
+ item.velocityDeficit ?? item.lossPercent ?? item.value?.[0] ?? 0;
|
|
|
|
|
+ return {
|
|
|
|
|
+ name: item.engineId || item.name || "",
|
|
|
|
|
+ value: [loss, confidencePercent],
|
|
|
|
|
+ };
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function shortEngineLabel(name) {
|
|
|
|
|
+ const text = String(name || "");
|
|
|
|
|
+ const match = text.match(/(\d+号风机)/);
|
|
|
|
|
+ return match ? match[1] : text;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const SCATTER2_QUADRANT_LABEL_LEFT = "72%";
|
|
|
|
|
+
|
|
|
|
|
+function computeScatter2Bounds(points, data = {}) {
|
|
|
|
|
+ const losses = points
|
|
|
|
|
+ .map((item) => Number(item.value?.[0]))
|
|
|
|
|
+ .filter((num) => Number.isFinite(num));
|
|
|
|
|
+ const confidences = points
|
|
|
|
|
+ .map((item) => Number(item.value?.[1]))
|
|
|
|
|
+ .filter((num) => Number.isFinite(num));
|
|
|
|
|
+
|
|
|
|
|
+ const lossMaxRaw = losses.length ? Math.max(...losses) : 30;
|
|
|
|
|
+ const confMinRaw = confidences.length ? Math.min(...confidences) : 65;
|
|
|
|
|
+ const confMaxRaw = confidences.length ? Math.max(...confidences) : 100;
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ xMin: data?.xAxis?.min ?? 0,
|
|
|
|
|
+ xMax: data?.xAxis?.max ?? Math.ceil(lossMaxRaw * 1.15),
|
|
|
|
|
+ yMin:
|
|
|
|
|
+ data?.yAxis?.min ??
|
|
|
|
|
+ Math.max(0, Math.floor(confMinRaw - Math.max(5, confMinRaw * 0.05))),
|
|
|
|
|
+ yMax:
|
|
|
|
|
+ data?.yAxis?.max ??
|
|
|
|
|
+ Math.min(100, Math.ceil(confMaxRaw + Math.max(2, confMaxRaw * 0.02))),
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function mapLossDelBarItems(items) {
|
|
|
|
|
+ if (!Array.isArray(items) || !items.length) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ categories: [],
|
|
|
|
|
+ lossPercentData: [],
|
|
|
|
|
+ turbulenceData: [],
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ return {
|
|
|
|
|
+ categories: items.map((item) => item.engineId || item.name || ""),
|
|
|
|
|
+ lossPercentData: items.map(
|
|
|
|
|
+ (item) => item.lossPercent ?? item.velocityDeficit ?? item.loss ?? 0,
|
|
|
|
|
+ ),
|
|
|
|
|
+ turbulenceData: items.map(
|
|
|
|
|
+ (item) =>
|
|
|
|
|
+ item.turbulenceIntensity ?? item.turbulence ?? item.delPercent ?? 0,
|
|
|
|
|
+ ),
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function buildLossDelSingleBarOption({
|
|
|
|
|
+ theme,
|
|
|
|
|
+ title,
|
|
|
|
|
+ categories,
|
|
|
|
|
+ data,
|
|
|
|
|
+ seriesName,
|
|
|
|
|
+ color,
|
|
|
|
|
+ yAxisName,
|
|
|
|
|
+}) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ title: {
|
|
|
|
|
+ text: title,
|
|
|
|
|
+ left: "center",
|
|
|
|
|
+ top: 10,
|
|
|
|
|
+ textStyle: { color: theme.title, fontSize: 14, fontWeight: "bold" },
|
|
|
|
|
+ },
|
|
|
|
|
+ tooltip: {
|
|
|
|
|
+ trigger: "axis",
|
|
|
|
|
+ valueFormatter: (value) => formatWakeMetric(value),
|
|
|
|
|
+ },
|
|
|
|
|
+ grid: {
|
|
|
|
|
+ left: "3%",
|
|
|
|
|
+ right: "4%",
|
|
|
|
|
+ bottom: "15%",
|
|
|
|
|
+ top: "18%",
|
|
|
|
|
+ containLabel: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ dataZoom: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: "slider",
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ xAxisIndex: 0,
|
|
|
|
|
+ height: 18,
|
|
|
|
|
+ bottom: 4,
|
|
|
|
|
+ start: 0,
|
|
|
|
|
+ end:
|
|
|
|
|
+ categories.length > 0
|
|
|
|
|
+ ? Math.min(100, (12 / categories.length) * 100)
|
|
|
|
|
+ : 100,
|
|
|
|
|
+ textStyle: {
|
|
|
|
|
+ color: theme.text,
|
|
|
|
|
+ },
|
|
|
|
|
+ brushSelect: false,
|
|
|
|
|
+ handleSize: 12,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: "inside",
|
|
|
|
|
+ xAxisIndex: 0,
|
|
|
|
|
+ zoomOnMouseWheel: true,
|
|
|
|
|
+ moveOnMouseMove: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ xAxis: {
|
|
|
|
|
+ type: "category",
|
|
|
|
|
+ data: categories,
|
|
|
|
|
+ axisLabel: { color: theme.text, rotate: 45, fontSize: 10 },
|
|
|
|
|
+ axisLine: { lineStyle: { color: theme.axis } },
|
|
|
|
|
+ },
|
|
|
|
|
+ yAxis: {
|
|
|
|
|
+ type: "value",
|
|
|
|
|
+ name: yAxisName,
|
|
|
|
|
+ nameTextStyle: { color, fontSize: 12 },
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ axisLabel: { color, formatter: (value) => formatWakeMetric(value) },
|
|
|
|
|
+ splitLine: { lineStyle: { color: theme.split } },
|
|
|
|
|
+ },
|
|
|
|
|
+ series: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: seriesName,
|
|
|
|
|
+ type: "bar",
|
|
|
|
|
+ barWidth: "45%",
|
|
|
|
|
+ data,
|
|
|
|
|
+ itemStyle: { color },
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ position: "top",
|
|
|
|
|
+ color,
|
|
|
|
|
+ fontSize: 10,
|
|
|
|
|
+ formatter: (params) => formatWakeMetric(params.value),
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function getLossDelLossBarOption(data) {
|
|
|
|
|
+ const theme = getWakeChartTheme();
|
|
|
|
|
+ const barMapped = mapLossDelBarItems(data?.items);
|
|
|
|
|
+
|
|
|
|
|
+ return buildLossDelSingleBarOption({
|
|
|
|
|
+ theme,
|
|
|
|
|
+ title: data?.lossTitle || "各机组日尺度发电量损失",
|
|
|
|
|
+ categories: barMapped.categories,
|
|
|
|
|
+ data: barMapped.lossPercentData,
|
|
|
|
|
+ seriesName: "发电量损失",
|
|
|
|
|
+ color: "#E85D5D",
|
|
|
|
|
+ yAxisName: "发电量损失(%)",
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-const barCategories = scatterData.map((item) => item.name);
|
|
|
|
|
-const lossData = scatterData.map((item) => item.value[2]);
|
|
|
|
|
-const delData = [
|
|
|
|
|
- 50.8, 54.6, 19.9, 17.2, 6.6, 20.7, 36.9, 24.6, 72.9, 3.5, 348.4, 13.5, 324.4,
|
|
|
|
|
- 14.1, 34.9, 3.6,
|
|
|
|
|
-];
|
|
|
|
|
|
|
+export function getLossDelTurbulenceBarOption(data) {
|
|
|
|
|
+ const theme = getWakeChartTheme();
|
|
|
|
|
+ const barMapped = mapLossDelBarItems(data?.items);
|
|
|
|
|
|
|
|
-export function getScatter1Option() {
|
|
|
|
|
|
|
+ return buildLossDelSingleBarOption({
|
|
|
|
|
+ theme,
|
|
|
|
|
+ title: data?.turbulenceTitle || "各机组附加湍流强度",
|
|
|
|
|
+ categories: barMapped.categories,
|
|
|
|
|
+ data: barMapped.turbulenceData,
|
|
|
|
|
+ seriesName: "附加湍流强度",
|
|
|
|
|
+ color: "#4D8BFF",
|
|
|
|
|
+ yAxisName: "附加湍流强度",
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function getScatter1Option(data) {
|
|
|
const theme = getWakeChartTheme();
|
|
const theme = getWakeChartTheme();
|
|
|
|
|
+ const points = mapLayoutScatterPoints(data?.points);
|
|
|
|
|
+ const visualMax = data?.visualMap?.max ?? 85;
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
backgroundColor: "transparent",
|
|
backgroundColor: "transparent",
|
|
|
title: {
|
|
title: {
|
|
|
- text: "风电场布局与机组日尺度发电量损失图(2025-10-24)",
|
|
|
|
|
|
|
+ text: data?.title || "风电场布局与机组日尺度发电量损失图",
|
|
|
left: "center",
|
|
left: "center",
|
|
|
top: 10,
|
|
top: 10,
|
|
|
textStyle: { color: theme.title, fontSize: 14, fontWeight: "bold" },
|
|
textStyle: { color: theme.title, fontSize: 14, fontWeight: "bold" },
|
|
|
},
|
|
},
|
|
|
tooltip: {
|
|
tooltip: {
|
|
|
formatter(params) {
|
|
formatter(params) {
|
|
|
- const val = params.value || params.data;
|
|
|
|
|
- return `${params.name}<br/>损失: ${Array.isArray(val) ? val[2] : val}%`;
|
|
|
|
|
|
|
+ const val = params.value || params.data?.value || [];
|
|
|
|
|
+ const east = Array.isArray(val) ? val[0] : 0;
|
|
|
|
|
+ const north = Array.isArray(val) ? val[1] : 0;
|
|
|
|
|
+ const loss = Array.isArray(val) ? val[2] : val;
|
|
|
|
|
+ return [
|
|
|
|
|
+ params.name,
|
|
|
|
|
+ `${SCATTER1_X_AXIS_NAME}: ${formatScatter1AxisValue(east)}`,
|
|
|
|
|
+ `${SCATTER1_Y_AXIS_NAME}: ${formatScatter1AxisValue(north)}`,
|
|
|
|
|
+ `损失: ${formatWakeMetric(loss)}%`,
|
|
|
|
|
+ ].join("<br/>");
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
grid: { left: "12%", right: "15%", bottom: "13%", top: "15%" },
|
|
grid: { left: "12%", right: "15%", bottom: "13%", top: "15%" },
|
|
|
xAxis: {
|
|
xAxis: {
|
|
|
- name: "东西方向坐标(米)",
|
|
|
|
|
- nameTextStyle: { color: theme.text, fontSize: 12, padding: [10, 0, 0, 0] },
|
|
|
|
|
|
|
+ name: SCATTER1_X_AXIS_NAME,
|
|
|
|
|
+ nameTextStyle: {
|
|
|
|
|
+ color: theme.text,
|
|
|
|
|
+ fontSize: 12,
|
|
|
|
|
+ padding: [10, 0, 0, 0],
|
|
|
|
|
+ },
|
|
|
nameLocation: "middle",
|
|
nameLocation: "middle",
|
|
|
- min: 333200,
|
|
|
|
|
- max: 333450,
|
|
|
|
|
|
|
+ min: data?.xAxis?.min,
|
|
|
|
|
+ max: data?.xAxis?.max,
|
|
|
axisLabel: {
|
|
axisLabel: {
|
|
|
color: theme.text,
|
|
color: theme.text,
|
|
|
- formatter(value) {
|
|
|
|
|
- return (value / 1000000).toFixed(4);
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ formatter: formatScatter1AxisValue,
|
|
|
},
|
|
},
|
|
|
axisLine: { lineStyle: { color: theme.axis } },
|
|
axisLine: { lineStyle: { color: theme.axis } },
|
|
|
axisTick: { show: true },
|
|
axisTick: { show: true },
|
|
|
splitLine: { lineStyle: { color: theme.split } },
|
|
splitLine: { lineStyle: { color: theme.split } },
|
|
|
},
|
|
},
|
|
|
yAxis: {
|
|
yAxis: {
|
|
|
- name: "南北方向坐标(米)",
|
|
|
|
|
- nameTextStyle: { color: theme.text, fontSize: 12, padding: [-50, 0, 35, 0] },
|
|
|
|
|
|
|
+ name: SCATTER1_Y_AXIS_NAME,
|
|
|
|
|
+ nameTextStyle: {
|
|
|
|
|
+ color: theme.text,
|
|
|
|
|
+ fontSize: 12,
|
|
|
|
|
+ padding: [-50, 0, 35, 0],
|
|
|
|
|
+ },
|
|
|
nameLocation: "middle",
|
|
nameLocation: "middle",
|
|
|
- min: 4172500,
|
|
|
|
|
- max: 4174000,
|
|
|
|
|
|
|
+ min: data?.yAxis?.min,
|
|
|
|
|
+ max: data?.yAxis?.max,
|
|
|
axisLabel: {
|
|
axisLabel: {
|
|
|
color: theme.text,
|
|
color: theme.text,
|
|
|
- formatter(value) {
|
|
|
|
|
- return (value / 1000000).toFixed(4);
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ formatter: formatScatter1AxisValue,
|
|
|
},
|
|
},
|
|
|
axisLine: { lineStyle: { color: theme.axis } },
|
|
axisLine: { lineStyle: { color: theme.axis } },
|
|
|
axisTick: { show: true },
|
|
axisTick: { show: true },
|
|
@@ -109,8 +282,8 @@ export function getScatter1Option() {
|
|
|
orient: "vertical",
|
|
orient: "vertical",
|
|
|
right: 0,
|
|
right: 0,
|
|
|
top: "center",
|
|
top: "center",
|
|
|
- min: 0,
|
|
|
|
|
- max: 85,
|
|
|
|
|
|
|
+ min: data?.visualMap?.min ?? 0,
|
|
|
|
|
+ max: visualMax,
|
|
|
inRange: {
|
|
inRange: {
|
|
|
color: ["#E8DFD9", "#DCB699", "#E8966A", "#DC4E4E", "#B82E2E"],
|
|
color: ["#E8DFD9", "#DCB699", "#E8966A", "#DC4E4E", "#B82E2E"],
|
|
|
},
|
|
},
|
|
@@ -131,161 +304,137 @@ export function getScatter1Option() {
|
|
|
fontSize: 9,
|
|
fontSize: 9,
|
|
|
formatter: "{b}",
|
|
formatter: "{b}",
|
|
|
},
|
|
},
|
|
|
- data: scatterData,
|
|
|
|
|
|
|
+ data: points,
|
|
|
itemStyle: { borderColor: "#999", borderWidth: 1 },
|
|
itemStyle: { borderColor: "#999", borderWidth: 1 },
|
|
|
},
|
|
},
|
|
|
],
|
|
],
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function getScatter2Option() {
|
|
|
|
|
|
|
+export function getScatter2Option(data) {
|
|
|
const theme = getWakeChartTheme();
|
|
const theme = getWakeChartTheme();
|
|
|
|
|
+ const points = mapWakeLossConfidentPoints(data?.points);
|
|
|
|
|
+ const bounds = computeScatter2Bounds(points, data);
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
title: {
|
|
title: {
|
|
|
- text: "日尺度损失与可信度散点图(2025-10-24)",
|
|
|
|
|
|
|
+ text: data?.title || "尾流速度损耗与置信度散点图",
|
|
|
left: "center",
|
|
left: "center",
|
|
|
top: 10,
|
|
top: 10,
|
|
|
textStyle: { color: theme.title, fontSize: 14 },
|
|
textStyle: { color: theme.title, fontSize: 14 },
|
|
|
},
|
|
},
|
|
|
- grid: { left: "8%", right: "8%", bottom: "13%", top: "15%" },
|
|
|
|
|
|
|
+ tooltip: {
|
|
|
|
|
+ formatter(params) {
|
|
|
|
|
+ const val = params.value || [];
|
|
|
|
|
+ return `${params.name}<br/>尾流速度损耗: ${formatWakeMetric(val[0])}<br/>结果可信度: ${formatWakePercent(val[1])}`;
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ grid: { left: "8%", right: "15%", bottom: "13%", top: "15%" },
|
|
|
xAxis: {
|
|
xAxis: {
|
|
|
- name: "发电量损失(%)",
|
|
|
|
|
- nameTextStyle: { color: theme.text, fontSize: 12, padding: [10, 0, 0, 0] },
|
|
|
|
|
|
|
+ name: data?.xAxis?.name || "尾流速度损耗",
|
|
|
|
|
+ nameTextStyle: {
|
|
|
|
|
+ color: theme.text,
|
|
|
|
|
+ fontSize: 12,
|
|
|
|
|
+ padding: [10, 0, 0, 0],
|
|
|
|
|
+ },
|
|
|
nameLocation: "middle",
|
|
nameLocation: "middle",
|
|
|
- min: 0,
|
|
|
|
|
- max: 90,
|
|
|
|
|
- axisLabel: { color: theme.text },
|
|
|
|
|
|
|
+ min: bounds.xMin,
|
|
|
|
|
+ max: bounds.xMax,
|
|
|
|
|
+ axisLabel: {
|
|
|
|
|
+ color: theme.text,
|
|
|
|
|
+ formatter: (value) => formatWakeMetric(value),
|
|
|
|
|
+ },
|
|
|
splitLine: { lineStyle: { color: theme.split } },
|
|
splitLine: { lineStyle: { color: theme.split } },
|
|
|
axisLine: { lineStyle: { color: theme.axis } },
|
|
axisLine: { lineStyle: { color: theme.axis } },
|
|
|
},
|
|
},
|
|
|
yAxis: {
|
|
yAxis: {
|
|
|
- name: "结果可信度(%)",
|
|
|
|
|
|
|
+ name: data?.yAxis?.name || "结果可信度(%)",
|
|
|
nameTextStyle: { color: theme.text, fontSize: 12 },
|
|
nameTextStyle: { color: theme.text, fontSize: 12 },
|
|
|
- min: 65,
|
|
|
|
|
- max: 98,
|
|
|
|
|
- axisLabel: { color: theme.text },
|
|
|
|
|
|
|
+ min: bounds.yMin,
|
|
|
|
|
+ max: bounds.yMax,
|
|
|
|
|
+ axisLabel: {
|
|
|
|
|
+ color: theme.text,
|
|
|
|
|
+ formatter: (value) => formatWakeMetric(value),
|
|
|
|
|
+ },
|
|
|
splitLine: { lineStyle: { color: theme.split } },
|
|
splitLine: { lineStyle: { color: theme.split } },
|
|
|
axisLine: { lineStyle: { color: theme.axis } },
|
|
axisLine: { lineStyle: { color: theme.axis } },
|
|
|
},
|
|
},
|
|
|
|
|
+ visualMap: {
|
|
|
|
|
+ type: "continuous",
|
|
|
|
|
+ orient: "vertical",
|
|
|
|
|
+ right: 0,
|
|
|
|
|
+ top: "center",
|
|
|
|
|
+ min: bounds.yMin,
|
|
|
|
|
+ max: bounds.yMax,
|
|
|
|
|
+ dimension: 1,
|
|
|
|
|
+ inRange: {
|
|
|
|
|
+ color: ["#E85D5D", "#E8966A", "#98d268", "#6bbf63", "#4CAF50", "#006837"],
|
|
|
|
|
+ },
|
|
|
|
|
+ textStyle: { color: theme.text, fontSize: 11 },
|
|
|
|
|
+ text: [
|
|
|
|
|
+ `结果可信度 ${formatWakeMetric(bounds.yMax)}%`,
|
|
|
|
|
+ `${formatWakeMetric(bounds.yMin)}%`,
|
|
|
|
|
+ ],
|
|
|
|
|
+ calculable: true,
|
|
|
|
|
+ itemWidth: 15,
|
|
|
|
|
+ },
|
|
|
graphic: [
|
|
graphic: [
|
|
|
{
|
|
{
|
|
|
type: "text",
|
|
type: "text",
|
|
|
- left: "70%",
|
|
|
|
|
- top: "25%",
|
|
|
|
|
|
|
+ left: SCATTER2_QUADRANT_LABEL_LEFT,
|
|
|
|
|
+ top: "22%",
|
|
|
style: {
|
|
style: {
|
|
|
text: "高损失 高可信度",
|
|
text: "高损失 高可信度",
|
|
|
fill: "#4CAF50",
|
|
fill: "#4CAF50",
|
|
|
fontSize: 14,
|
|
fontSize: 14,
|
|
|
fontWeight: "bold",
|
|
fontWeight: "bold",
|
|
|
|
|
+ textAlign: "left",
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
type: "text",
|
|
type: "text",
|
|
|
- left: "65%",
|
|
|
|
|
- top: "75%",
|
|
|
|
|
|
|
+ left: SCATTER2_QUADRANT_LABEL_LEFT,
|
|
|
|
|
+ top: "72%",
|
|
|
style: {
|
|
style: {
|
|
|
text: "高损失 低可信度",
|
|
text: "高损失 低可信度",
|
|
|
fill: "#E85D5D",
|
|
fill: "#E85D5D",
|
|
|
fontSize: 14,
|
|
fontSize: 14,
|
|
|
fontWeight: "bold",
|
|
fontWeight: "bold",
|
|
|
|
|
+ textAlign: "left",
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
],
|
|
],
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
type: "scatter",
|
|
type: "scatter",
|
|
|
- symbolSize: 15,
|
|
|
|
|
|
|
+ symbolSize: 16,
|
|
|
label: {
|
|
label: {
|
|
|
show: true,
|
|
show: true,
|
|
|
position: "top",
|
|
position: "top",
|
|
|
color: theme.text,
|
|
color: theme.text,
|
|
|
- fontSize: 10,
|
|
|
|
|
- formatter: "{b}",
|
|
|
|
|
|
|
+ fontSize: 9,
|
|
|
|
|
+ formatter: (params) => shortEngineLabel(params.name),
|
|
|
},
|
|
},
|
|
|
- data: scatter2Data,
|
|
|
|
|
- itemStyle: { shadowBlur: 8, shadowColor: "rgba(0, 0, 0, 0.3)" },
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- };
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-export function getBarOption() {
|
|
|
|
|
- const theme = getWakeChartTheme();
|
|
|
|
|
-
|
|
|
|
|
- return {
|
|
|
|
|
- title: {
|
|
|
|
|
- text: "各机组日尺度发电量损失与相对DEL指标(2025-10-24)",
|
|
|
|
|
- left: "center",
|
|
|
|
|
- top: 10,
|
|
|
|
|
- textStyle: { color: theme.title, fontSize: 16, fontWeight: "bold" },
|
|
|
|
|
- },
|
|
|
|
|
- legend: {
|
|
|
|
|
- data: ["发电量损失(%)", "相对DEL指标(%)"],
|
|
|
|
|
- top: 40,
|
|
|
|
|
- textStyle: { color: theme.text },
|
|
|
|
|
- },
|
|
|
|
|
- grid: {
|
|
|
|
|
- left: "3%",
|
|
|
|
|
- right: "4%",
|
|
|
|
|
- bottom: "15%",
|
|
|
|
|
- top: "20%",
|
|
|
|
|
- containLabel: true,
|
|
|
|
|
- },
|
|
|
|
|
- xAxis: {
|
|
|
|
|
- type: "category",
|
|
|
|
|
- data: barCategories,
|
|
|
|
|
- axisLabel: { color: theme.text, rotate: 45, fontSize: 10 },
|
|
|
|
|
- axisLine: { lineStyle: { color: theme.axis } },
|
|
|
|
|
- },
|
|
|
|
|
- yAxis: [
|
|
|
|
|
- {
|
|
|
|
|
- type: "value",
|
|
|
|
|
- name: "发电量损失(%)",
|
|
|
|
|
- nameTextStyle: { color: "#E85D5D", fontSize: 12 },
|
|
|
|
|
- min: 0,
|
|
|
|
|
- max: 100,
|
|
|
|
|
- axisLabel: { color: "#E85D5D", formatter: "{value}%" },
|
|
|
|
|
- splitLine: { lineStyle: { color: theme.split } },
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- type: "value",
|
|
|
|
|
- name: "相对DEL指标(%)",
|
|
|
|
|
- nameTextStyle: { color: "#4D8BFF", fontSize: 12 },
|
|
|
|
|
- min: 0,
|
|
|
|
|
- max: 400,
|
|
|
|
|
- axisLabel: { color: "#4D8BFF", formatter: "{value}%" },
|
|
|
|
|
- splitLine: { show: false },
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- series: [
|
|
|
|
|
- {
|
|
|
|
|
- name: "发电量损失(%)",
|
|
|
|
|
- type: "bar",
|
|
|
|
|
- barWidth: "30%",
|
|
|
|
|
- data: lossData,
|
|
|
|
|
- itemStyle: { color: "#E85D5D" },
|
|
|
|
|
- label: {
|
|
|
|
|
- show: true,
|
|
|
|
|
- position: "top",
|
|
|
|
|
- color: "#E85D5D",
|
|
|
|
|
- fontSize: 10,
|
|
|
|
|
|
|
+ labelLayout: {
|
|
|
|
|
+ hideOverlap: false,
|
|
|
|
|
+ moveOverlap: "shiftY",
|
|
|
},
|
|
},
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- name: "相对DEL指标(%)",
|
|
|
|
|
- type: "bar",
|
|
|
|
|
- barWidth: "30%",
|
|
|
|
|
- yAxisIndex: 1,
|
|
|
|
|
- data: delData,
|
|
|
|
|
- itemStyle: { color: "#4D8BFF" },
|
|
|
|
|
- label: {
|
|
|
|
|
- show: true,
|
|
|
|
|
- position: "top",
|
|
|
|
|
- color: "#4D8BFF",
|
|
|
|
|
- fontSize: 10,
|
|
|
|
|
|
|
+ emphasis: {
|
|
|
|
|
+ scale: 1.2,
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ formatter: (params) => params.name,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ data: points,
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ borderColor: "rgba(255, 255, 255, 0.45)",
|
|
|
|
|
+ borderWidth: 1,
|
|
|
|
|
+ shadowBlur: 8,
|
|
|
|
|
+ shadowColor: "rgba(0, 0, 0, 0.3)",
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
],
|
|
],
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
+
|