123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- import puppeteer from "puppeteer";
- import fs from "fs-extra";
- import path from "path";
- import FormData from "form-data";
- import { colorSchemes } from "../colors.js";
- export const generateTwoDMarkersChart1 = async (data) => {
- try {
- // 创建临时目录
- const tempDir = path.join(process.cwd(), "images");
- await fs.ensureDir(tempDir);
- const tempFilePath = path.join(
- tempDir,
- `temp_scatter_chart_${Date.now()}.png`
- );
- // 获取 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} <br> ${data.yaixs}: %{y} <br> 时间: %{customdata}<extra></extra>`,
- 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 = `
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>2D 散点图</title>
- <script>${plotlyContent}</script>
- </head>
- <body>
- <div id="chart" style="width: 100%; height: 600px"></div>
- <script>
- const traces = [${JSON.stringify(scatterTrace)}${
- lineTrace ? `, ${JSON.stringify(lineTrace)}` : ""
- }];
- const layout = ${JSON.stringify(layout)};
- Plotly.newPlot('chart', traces, layout, { responsive: true }).then(() => {
- window.chartRendered = true; // 确保在图表渲染完成后设置
- console.log("图表渲染完成");
- }).catch((error) => {
- console.error("图表渲染错误:", error); // 捕获渲染错误
- });
- </script>
- </body>
- </html>
- `;
- // 设置页面内容
- 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: "png",
- });
- // 上传图片到服务器
- const formData = new FormData();
- formData.append("file", fs.createReadStream(tempFilePath));
- return formData;
- } catch (error) {
- console.error("生成2D散点图失败:", error);
- throw error;
- } finally {
- await browser.close();
- }
- } catch (error) {
- console.error("生成2D散点图失败:", error);
- throw error;
- }
- };
|