HeatmapCharts.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * @Author: your name
  3. * @Date: 2025-04-14 11:15:35
  4. * @LastEditTime: 2025-05-21 15:10:19
  5. * @LastEditors: bogon
  6. * @Description: In User Settings Edit
  7. * @FilePath: /performance-test/downLoadServer/src/server/utils/chartsCom/HeatmapCharts.js
  8. */
  9. import puppeteer from "puppeteer";
  10. import fs from "fs-extra";
  11. import path from "path";
  12. import FormData from "form-data";
  13. import { colorSchemes } from "../colors.js";
  14. import axios from "axios";
  15. export const generateHeatmapChart = async (data, bucketName, objectName) => {
  16. try {
  17. console.log("开始生成热力图...");
  18. console.log("数据:", data);
  19. // 创建临时目录
  20. const tempDir = path.join(process.cwd(), "images");
  21. await fs.ensureDir(tempDir);
  22. const tempFilePath = path.join(
  23. tempDir,
  24. `temp_heatmap_chart_${Date.now()}.jpeg`
  25. );
  26. // 获取 plotly.js 的绝对路径
  27. const plotlyPath = path.join(
  28. process.cwd(),
  29. "src",
  30. "public",
  31. "js",
  32. "plotly-3.0.1.min.js"
  33. );
  34. const plotlyContent = await fs.readFile(plotlyPath, "utf-8");
  35. // 创建浏览器实例
  36. const browser = await puppeteer.launch({
  37. headless: "new",
  38. executablePath: `${process.env.CHROME_PATH}`, // 根据系统改路径
  39. args: ["--no-sandbox", "--disable-setuid-sandbox"],
  40. });
  41. try {
  42. const page = await browser.newPage();
  43. // 准备图表数据
  44. const chartDataset = data.data[0];
  45. const trace = {
  46. type: "heatmap",
  47. x: chartDataset.xData,
  48. y: chartDataset.yData,
  49. z: chartDataset.ZData,
  50. zmin: 0, // 最小值
  51. zmax: 100, // 最大值
  52. colorscale: [
  53. [0, "#E1ECC5"], // 0% - 50%
  54. [0.5, "#E1ECC5"], // 50%
  55. [0.5, "#9BC8C1"], // 50% - 85%
  56. [0.85, "#9BC8C1"], // 85%
  57. [0.85, "#5783B3"], // 85% - 100%
  58. [1, "#5783B3"], // 100%
  59. ],
  60. text: chartDataset.ZData.map((row) =>
  61. row.map((value) => value.toString())
  62. ),
  63. hoverinfo: "text", // Hover时显示文本
  64. showscale: true, // 显示颜色条
  65. texttemplate: "%{text}", // 在热图块上显示z值
  66. xgap: 2, // 设置水平方向格子之间的间距
  67. ygap: 2, // 设置垂直方向格子之间的间距
  68. };
  69. // 准备布局配置
  70. const layout = {
  71. showlegend: false,
  72. autosize: true,
  73. title: {
  74. text: chartDataset.title,
  75. font: {
  76. size: 16,
  77. weight: "bold",
  78. },
  79. },
  80. xaxis: {
  81. title: data.xaixs || "X轴",
  82. tickvals: chartDataset.xData,
  83. ticktext: chartDataset.xData,
  84. tickmode: "array",
  85. tickfont: {
  86. size: 12,
  87. },
  88. },
  89. yaxis: {
  90. title: data.yaixs || "Y轴",
  91. tickvals: chartDataset.yData,
  92. ticktext: chartDataset.yData,
  93. tickmode: "array",
  94. tickfont: {
  95. size: 12,
  96. },
  97. },
  98. plot_bgcolor: "white",
  99. gridcolor: "#d3d3d3", // 设置网格线颜色
  100. };
  101. // 准备 HTML 内容
  102. const htmlContent = `
  103. <!DOCTYPE html>
  104. <html>
  105. <head>
  106. <meta charset="UTF-8">
  107. <title>热力图</title>
  108. <script>${plotlyContent}</script>
  109. </head>
  110. <body>
  111. <div id="chart" style="width: 100%; height: 450px"></div>
  112. <script>
  113. window.chartRendered = false;
  114. const trace = ${JSON.stringify(trace)};
  115. const layout = ${JSON.stringify(layout)};
  116. Plotly.newPlot('chart', [trace], layout, { responsive: true }).then(() => {
  117. window.chartRendered = true;
  118. });
  119. </script>
  120. </body>
  121. </html>
  122. `;
  123. // 设置页面内容
  124. await page.setContent(htmlContent, {
  125. waitUntil: "networkidle0",
  126. });
  127. // 等待图表渲染完成,延长超时时间
  128. await page.waitForFunction(() => window.chartRendered === true, {
  129. timeout: 120000, // 延长到 120 秒
  130. });
  131. // 截图并保存到临时文件
  132. const chartElement = await page.$("#chart");
  133. await chartElement.screenshot({
  134. path: tempFilePath,
  135. type: "jpeg",
  136. });
  137. // 上传图片到服务器
  138. const formData = new FormData();
  139. formData.append("file", fs.createReadStream(tempFilePath));
  140. // const response = await axios.post(
  141. // "http://10.10.10.11:8080/upload",
  142. // formData,
  143. // {
  144. // headers: {
  145. // ...formData.getHeaders(),
  146. // },
  147. // }
  148. // );
  149. // 返回图片URL
  150. // return response.data.data;
  151. // return formData;
  152. // 发送上传请求
  153. const response = await axios.post(
  154. `${process.env.API_BASE_URL}/examples/upload`,
  155. { filePath: tempFilePath, bucketName, objectName }
  156. );
  157. return response?.data?.url;
  158. } catch (error) {
  159. console.error("生成热力图失败:", error);
  160. throw error;
  161. } finally {
  162. await browser.close();
  163. }
  164. } catch (error) {
  165. console.error("生成热力图失败:", error);
  166. throw error;
  167. }
  168. };