import puppeteer from "puppeteer"; import fs from "fs-extra"; import path from "path"; import FormData from "form-data"; import { colorSchemes } from "../colors.js"; import axios from "axios"; export const generateTwoDMarkersChart1 = async ( data, bucketName, objectName ) => { try { // 创建临时目录 const tempDir = path.join(process.cwd(), "images"); await fs.ensureDir(tempDir); const tempFilePath = path.join( tempDir, `temp_scatter_chart_${Date.now()}.jpeg` ); // 获取 plotly.js 的绝对路径 const plotlyPath = path.join( process.cwd(), "src", "public", "js", "plotly-3.0.1.min.js" ); const plotlyContent = await fs.readFile(plotlyPath, "utf-8"); // 创建浏览器实例 const browser = await puppeteer.launch({ headless: "new", args: ["--no-sandbox", "--disable-setuid-sandbox"], }); try { const page = await browser.newPage(); // 提取散点数据和线数据 const scatterData = data.data.filter( (item) => item.engineName !== "合同功率曲线" )[0]; // 点数据 const lineData = data.data.filter( (item) => item.engineName === "合同功率曲线" || item.enginName === "合同功率曲线" )[0]; // 线数据 // 提取唯一时间标签,并计算 tickvals 和 ticktext const uniqueTimeLabels = scatterData.colorbar ? [...new Set(scatterData.colorbar)] : [...new Set(scatterData.color)]; const tickvals = uniqueTimeLabels.map((_, index) => index + 1); const ticktext = uniqueTimeLabels.map((dateStr) => { const date = new Date(dateStr); return date.toLocaleDateString("en-CA", { year: "numeric", month: "2-digit", }); }); const timeMapping = uniqueTimeLabels.reduce((acc, curr, index) => { acc[curr] = index + 1; return acc; }, {}); // 计算颜色值映射 let colorValues = scatterData.colorbar ? scatterData.colorbar.map((date) => timeMapping[date]) : scatterData.color.map((date) => timeMapping[date]); // 绘制散点图 const scatterTrace = { x: scatterData.xData, y: scatterData.yData, mode: "markers", type: "scattergl", // 使用 scattergl 提高性能 text: scatterData.engineName, // 提示文本 marker: { color: colorValues, colorscale: [ [0, "#F9FDD2"], [0.15, "#E9F6BD"], [0.3, "#C2E3B9"], [0.45, "#8AC8BE"], [0.6, "#5CA8BF"], [0.75, "#407DB3"], [0.9, "#2E4C9A"], [1, "#1B2973"], ], size: new Array(scatterData.xData.length).fill(6), // 点的大小 }, hovertemplate: `${data.xaixs}: %{x}
${data.yaixs}: %{y}
时间: %{customdata}`, customdata: scatterData.colorbar || scatterData.color, // 将格式化后的时间存入 customdata }; // 绘制线图 let lineTrace = {}; if (lineData) { lineTrace = { x: lineData.xData, y: lineData.yData, mode: "lines+markers", // 线和点同时显示 type: "scattergl", // 使用 scattergl 类型 text: lineData.engineName, // 提示文本 line: { color: "red", // 线条颜色 }, }; } console.log(lineData, lineTrace, "2222"); // 图表布局 const layout = { title: { text: scatterData.title, font: { size: 16, weight: "bold", }, }, xaxis: { title: { text: data.xaixs, }, gridcolor: "rgb(255,255,255)", tickcolor: "rgb(255,255,255)", backgroundcolor: "#e5ecf6", showbackground: true, }, yaxis: { title: { text: data.yaixs, }, gridcolor: "rgb(255,255,255)", tickcolor: "rgb(255,255,255)", backgroundcolor: "#e5ecf6", showbackground: true, }, showlegend: false, plot_bgcolor: "#e5ecf6", gridcolor: "#fff", }; // 准备 HTML 内容 const htmlContent = ` 2D 散点图
`; // 设置页面内容 await page.setContent(htmlContent, { waitUntil: "networkidle0", }); // 等待图表渲染完成,延长超时时间 await page.waitForFunction(() => window.chartRendered === true, { timeout: 150000, // 延长到 150 秒 }); // 截图并保存到临时文件 const chartElement = await page.$("#chart"); await chartElement.screenshot({ path: tempFilePath, type: "jpeg", }); // 上传图片到服务器 const formData = new FormData(); formData.append("file", fs.createReadStream(tempFilePath)); // return formData; // 发送上传请求 const response = await axios.post( `${process.env.API_BASE_URL}/examples/upload`, { filePath: tempFilePath, bucketName, objectName } ); return response?.data?.url; } catch (error) { console.error("生成2D散点图失败:", error); throw error; } finally { await browser.close(); } } catch (error) { console.error("生成2D散点图失败:", error); throw error; } };