123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- /*
- * @Author: your name
- * @Date: 2025-04-14 17:49:33
- * @LastEditTime: 2025-07-14 16:04:07
- * @LastEditors: bogon
- * @Description: In User Settings Edit
- * @FilePath: /performance-test/downLoadServer/src/server/utils/chartsCom/Time3DChart.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";
- // 格式化日期为 YY-MM 格式
- const formatDate = (dateString) => {
- const date = new Date(dateString);
- const year = date.getFullYear(); // 获取年份后两位
- const month = ("0" + (date.getMonth() + 1)).slice(-2); // 获取月份并确保两位数
- return `${year}-${month}`;
- };
- export const generateTime3DChart = async (data, bucketName, objectName) => {
- try {
- // 创建临时目录
- const tempDir = path.join(process.cwd(), "images");
- await fs.ensureDir(tempDir);
- const tempFilePath = path.join(
- tempDir,
- `temp_heatmap_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",
- "--window-size=1920,1080",
- ],
- });
- try {
- const page = await browser.newPage();
- // 准备图表数据
- const uniqueMonths = Array.from(
- new Set(data.data[0].yData.map((date) => formatDate(date)))
- );
- // 设置每个月份对应的颜色
- const monthColors = colorSchemes[0].colors;
- const traces = uniqueMonths.map((month, monthIndex) => {
- const monthData = data.data[0].yData
- .map((date, index) => (formatDate(date) === month ? index : -1))
- .filter((index) => index !== -1);
- return {
- x: monthData.map((index) => data.data[0].xData[index]), // 发电机转速
- y: monthData.map((index) => data.data[0].yData[index]), // 时间
- z: monthData.map((index) => data.data[0].zData[index]), // 有功功率
- mode: "markers", // 根据需要设置模式
- type: "scatter3d",
- marker: {
- size: 1, // 使用动态点大小
- color: monthColors[monthIndex], // 使用配色方案
- colorscale: "YlGnBu",
- },
- name: ` ${month}`,
- };
- });
- // 准备布局配置
- const layout = {
- title: {
- text: data.data[0].title,
- font: {
- size: 16,
- weight: "bold",
- },
- },
- scene: {
- xaxis: {
- gridcolor: "#fff",
- backgroundcolor: "#e0e7f1",
- showbackground: true,
- linecolor: "black",
- ticks: "outside",
- // ticklen: 10,
- tickcolor: "black",
- zeroline: false,
- tickangle: -10,
- title: {
- text: data.xaixs,
- standoff: 100,
- },
- },
- yaxis: {
- type: "category", // 让 Y 轴按类别均匀分布
- categoryorder: "category ascending", // 按类别字母顺序排列
- type: "date",
- tickformat: "%Y-%m",
- // dtick: "M3",//显式设置每3个月一个刻度
- nticks: 3,
- gridcolor: "#fff",
- tickcolor: "#e5ecf6",
- backgroundcolor: "#e0e7f1",
- showbackground: true,
- linecolor: "black",
- ticks: "outside",
- tickcolor: "black",
- zeroline: false,
- tickangle: 25,
- title: {
- text: data.yaixs,
- },
- },
- zaxis: {
- gridcolor: "#fff",
- tickcolor: "#fff",
- backgroundcolor: "#e0e7f1",
- showbackground: true,
- linecolor: "black",
- ticks: "outside",
- tickcolor: "black",
- zeroline: false,
- nticks: 3,
- tickangle: -90,
- title: {
- text: data.zaixs,
- },
- },
- plot_bgcolor: "#e5ecf6",
- gridcolor: "#fff",
- bgcolor: "#e5ecf6", // 设置背景颜色
- aspectmode: "manual",
- aspectratio: {
- x: 2.0000000000000018,
- y: 1.5454545454545465,
- z: 0.9090909090909098,
- },
- camera: {
- up: {
- x: 0.19380723218588866,
- y: 0.2540224158731985,
- z: 0.9475818534492884,
- },
- center: {
- x: -0.052807476121180814,
- y: 0.02451796399554085,
- z: -0.022911006648570736,
- },
- eye: {
- x: -2.126389777109588,
- y: -2.5514260394238466,
- z: 1.091739681861482,
- },
- projection: {
- type: "orthographic",
- },
- },
- },
- margin: { t: 50, b: 50, l: 50, r: 50 },
- staticPlot: false,
- showlegend: true,
- legend: {
- itemsizing: "constant", // ✅ 统一图例 marker 大小
- font: {
- size: 12,
- },
- marker: {
- size: 10, // 图例中点的大小
- },
- },
- };
- // 准备 HTML 内容
- const htmlContent = `
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>3D图</title>
- <script>${plotlyContent}</script>
- </head>
- <body>
- <div id="chart" style="width: 100%; height: 500px"></div>
- <script>
- const traces = ${JSON.stringify(traces)};
- const layout = ${JSON.stringify(layout)};
- Plotly.newPlot('chart', traces, layout, { responsive: true }).then(() => {
- window.chartRendered = true; // 确保在图表渲染完成后设置
-
- }).catch((error) => {
- console.error("图表渲染错误:", error); // 捕获渲染错误
- });
- </script>
- </body>
- </html>
- `;
- // 设置页面内容
- await page.setContent(htmlContent, {
- waitUntil: "networkidle0",
- });
- // 等待图表渲染完成,延长超时时间
- await page.waitForFunction(() => window.chartRendered === true, {
- timeout: 150000, // 延长到 120 秒
- });
- // 截图并保存到临时文件
- 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("生成3D图失败:", error);
- throw error;
- } finally {
- await browser.close();
- }
- } catch (error) {
- console.error("生成3D图失败:", error);
- throw error;
- }
- };
|