/* * @Author: your name * @Date: 2025-04-25 16:19:33 * @LastEditTime: 2025-07-08 14:40:29 * @LastEditors: bogon * @Description: In User Settings Edit * @FilePath: /downLoadServer/src/server/utils/chartsCom/TwoDMarkersChart.js */ 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 generateTwoDMarkersChart = 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", // 根据系统改路径 executablePath: `${process.env.CHROME_PATH}`, // 根据系统改路径 args: ["--no-sandbox", "--disable-setuid-sandbox"], }); try { const page = await browser.newPage(); // 准备图表数据 const chartDataset = data.data[0]; const uniqueTimeLabels = chartDataset.colorbar && chartDataset.colorbar.length === chartDataset.xData.length ? [...new Set(chartDataset.colorbar)] : [...new Set(chartDataset.yData)]; const ticktext = uniqueTimeLabels.map((label) => label); const tickvals = uniqueTimeLabels.map((_, index) => index + 1); const timeMapping = uniqueTimeLabels.reduce((acc, curr, index) => { acc[curr] = index + 1; return acc; }, {}); // 获取 colorbar 的最小值和最大值来计算比例值 const minValue = Math.min(...new Set(uniqueTimeLabels)); const maxValue = Math.max(...new Set(uniqueTimeLabels)); const colorStops = [ colorSchemes[0].colors[0], colorSchemes[0].colors[4], colorSchemes[0].colors[8], colorSchemes[0].colors[12], ]; // 计算渐变比例 const colors = colorStops.map((color, index) => { const proportion = index / (colorStops.length - 1); // 计算比例值 (0, 1/3, 2/3, 1) return [proportion, color]; // 创建比例-颜色映射 }); // 确保 colors 至少有 2 种颜色,否则使用默认颜色 if (colors.length < 2) { colors.push([1, colorStops[colorStops.length - 1] || "#1B2973"]); } // 计算颜色值映射 let colorValues = chartDataset.colorbar && chartDataset.colorbar.length === chartDataset.xData.length ? chartDataset.colorbar.map((date) => timeMapping[date]) : chartDataset.yData.map((date) => timeMapping[date]); // 绘制 2D 散点图 const trace = { x: chartDataset.xData, y: chartDataset.yData, mode: "markers", type: "scattergl", // 使用 scattergl 提高性能 text: chartDataset.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(chartDataset.xData.length).fill(6), // 点的大小 }, }; // 图表布局 const layout = { title: { text: chartDataset.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: true, plot_bgcolor: "#e5ecf6", gridcolor: "#fff", }; // 准备 HTML 内容 const htmlContent = `