TwoDMarkersChart1.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import { renderChart } from "../chartService/index.js";
  2. import { colorSchemes } from "../colors.js";
  3. export const generateTwoDMarkersChart1 = async (
  4. data,
  5. bucketName,
  6. objectName,
  7. ) => {
  8. try {
  9. // ✅ 1. 数据拆分(修复 enginName 拼写问题🔥)
  10. const scatterData = data.data.find(
  11. (item) => item.engineName !== "合同功率曲线",
  12. );
  13. const lineData = data.data.find(
  14. (item) =>
  15. item.engineName === "合同功率曲线" || item.enginName === "合同功率曲线",
  16. );
  17. if (!scatterData) {
  18. throw new Error("scatterData 不存在");
  19. }
  20. // ✅ 2. 颜色数据源
  21. const rawColorData =
  22. scatterData.colorbar?.length === scatterData.xData.length
  23. ? scatterData.colorbar
  24. : scatterData.color;
  25. const uniqueLabels = [...new Set(rawColorData)];
  26. const tickvals = uniqueLabels.map((_, i) => i + 1);
  27. const ticktext = uniqueLabels.map((dateStr) => {
  28. const date = new Date(dateStr);
  29. if (isNaN(date)) return dateStr; // 防止非法时间🔥
  30. const y = date.getFullYear();
  31. const m = String(date.getMonth() + 1).padStart(2, "0");
  32. return `${y}-${m}`;
  33. });
  34. const mapping = uniqueLabels.reduce((acc, cur, i) => {
  35. acc[cur] = i + 1;
  36. return acc;
  37. }, {});
  38. // ✅ 3. 颜色渐变(安全版)
  39. const colors = colorSchemes?.[0]?.colors || [];
  40. const safePick = (i) => colors[i] || colors[0] || "#1B2973";
  41. const colorStops = [safePick(0), safePick(4), safePick(8), safePick(12)];
  42. const colorscale = colorStops.map((c, i) => [
  43. i / (colorStops.length - 1),
  44. c,
  45. ]);
  46. if (colorscale.length < 2) {
  47. colorscale.push([1, safePick(0)]);
  48. }
  49. // ✅ 4. 映射颜色
  50. const colorValues = rawColorData.map((v) => mapping[v]);
  51. // ⚠️ 性能优化
  52. const pointCount = scatterData.xData.length;
  53. const markerSize = pointCount > 5000 ? 3 : 6;
  54. // ✅ 5. scatter trace
  55. const scatterTrace = {
  56. x: scatterData.xData,
  57. y: scatterData.yData,
  58. type: "scattergl",
  59. mode: "markers",
  60. name: scatterData.engineName,
  61. marker: {
  62. color: colorValues,
  63. colorscale,
  64. size: markerSize,
  65. colorbar: {
  66. title: { text: scatterData.colorbartitle || "时间" },
  67. tickvals,
  68. ticktext,
  69. },
  70. line: {
  71. color: "#fff",
  72. width: 0.3,
  73. },
  74. },
  75. customdata: rawColorData,
  76. hovertemplate:
  77. `${data.xaixs}: %{x}<br>` +
  78. `${data.yaixs}: %{y}<br>` +
  79. `时间: %{customdata}<extra></extra>`,
  80. };
  81. // ✅ 6. 合同曲线(优化:避免空对象加入🔥)
  82. const traces = [scatterTrace];
  83. if (lineData?.xData?.length && lineData?.yData?.length) {
  84. traces.push({
  85. x: lineData.xData,
  86. y: lineData.yData,
  87. type: "scatter",
  88. mode: "lines+markers",
  89. name: "合同功率曲线",
  90. line: { color: "red" },
  91. marker: { color: "red", size: 4 },
  92. });
  93. }
  94. // ✅ 7. layout
  95. const layout = {
  96. title: {
  97. text: scatterData.title || "散点图",
  98. font: { size: 16 },
  99. },
  100. xaxis: {
  101. title: data.xaixs,
  102. gridcolor: "rgb(255,255,255)",
  103. tickcolor: "rgb(255,255,255)",
  104. backgroundcolor: "#e5ecf6",
  105. showbackground: true,
  106. showline: true, // ✅ 显示 X 轴轴线
  107. zeroline: false,
  108. linecolor: "#ffffff", // ✅ X 轴轴线颜色设为白色
  109. },
  110. yaxis: {
  111. title: data.yaixs,
  112. gridcolor: "rgb(255,255,255)",
  113. tickcolor: "rgb(255,255,255)",
  114. backgroundcolor: "#e5ecf6",
  115. showbackground: true,
  116. showline: true, // ✅ 显示 X 轴轴线
  117. zeroline: false,
  118. linecolor: "#ffffff", // ✅ X 轴轴线颜色设为白色
  119. },
  120. showlegend: false,
  121. plot_bgcolor: "#e5ecf6",
  122. paper_bgcolor: "#e5ecf6",
  123. };
  124. // ✅ 8. 渲染
  125. const url = await renderChart({
  126. traces,
  127. layout,
  128. bucketName,
  129. objectName,
  130. });
  131. return url;
  132. } catch (error) {
  133. console.error("❌ 生成2D散点图失败:", error);
  134. throw error;
  135. }
  136. };