|
@@ -1,7 +1,7 @@
|
|
|
<!--
|
|
|
* @Author: your name
|
|
|
* @Date: 2024-09-11 14:30:17
|
|
|
- * @LastEditTime: 2025-07-10 10:38:19
|
|
|
+ * @LastEditTime: 2025-07-25 16:06:58
|
|
|
* @LastEditors: bogon
|
|
|
* @Description: In User Settings Edit
|
|
|
* @FilePath: /performance-test/src/views/performance/components/chartsCom/BarChart.vue
|
|
@@ -11,7 +11,10 @@
|
|
|
<div>
|
|
|
<!-- 图表控制面板 -->
|
|
|
<div style="display: flex; align-items: center">
|
|
|
- <div style="margin-right: 20px; display: flex; align-items: center">
|
|
|
+ <div
|
|
|
+ v-if="chartData.data.length < 2"
|
|
|
+ style="margin-right: 20px; display: flex; align-items: center"
|
|
|
+ >
|
|
|
<el-color-picker
|
|
|
size="small"
|
|
|
v-model="color1"
|
|
@@ -20,6 +23,31 @@
|
|
|
></el-color-picker>
|
|
|
<span style="margin-left: 10px">自定义颜色</span>
|
|
|
</div>
|
|
|
+ <el-select
|
|
|
+ v-else
|
|
|
+ size="small"
|
|
|
+ v-model="color1"
|
|
|
+ @change="updateChartColor"
|
|
|
+ placeholder="选择配色方案"
|
|
|
+ style="width: 200px"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="(scheme, index) in colorSchemes"
|
|
|
+ :key="index"
|
|
|
+ :label="scheme.label"
|
|
|
+ :value="scheme.colors"
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ v-for="color in scheme.colors.slice(0, 8)"
|
|
|
+ :style="{
|
|
|
+ background: color,
|
|
|
+ width: '20px',
|
|
|
+ height: '20px',
|
|
|
+ display: 'inline-block',
|
|
|
+ }"
|
|
|
+ ></span>
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
<div>
|
|
|
<el-button size="small" @click="toggleChartType">
|
|
|
切换为{{ chartType === "bar" ? "折线图" : "柱状图" }}
|
|
@@ -31,6 +59,7 @@
|
|
|
<div
|
|
|
v-loading="loading"
|
|
|
:id="`bar-chart-${inds}`"
|
|
|
+ :ref="`bar-chart${inds}`"
|
|
|
style="width: 100%; height: 400px"
|
|
|
>
|
|
|
<el-empty v-if="isError" description="请求失败"></el-empty>
|
|
@@ -42,8 +71,9 @@
|
|
|
import { nextTick } from "vue"; // 导入 nextTick
|
|
|
import Plotly from "plotly.js-dist";
|
|
|
import axios from "axios";
|
|
|
+import { colorSchemes } from "@/views/overview/js/colors";
|
|
|
import { myMixin } from "@/mixins/chartRequestMixin";
|
|
|
-
|
|
|
+import { mapState } from "vuex";
|
|
|
export default {
|
|
|
props: {
|
|
|
fileAddr: {
|
|
@@ -68,14 +98,46 @@ export default {
|
|
|
yaixs: "",
|
|
|
data: [],
|
|
|
},
|
|
|
+ color1: null, // 默认颜色
|
|
|
chartType: "bar", // 当前图表类型 ('bar' 或 'scatter')
|
|
|
- color1: "#588CF0", // 默认颜色
|
|
|
+ // color1: "#588CF0", // 默认颜色
|
|
|
+ // 配色方案列表(每个方案是一个颜色数组)
|
|
|
+ colorSchemes: colorSchemes,
|
|
|
+ colors: [...colorSchemes[0].colors],
|
|
|
// normalRangeMin: 5, // 最低范围
|
|
|
// normalRangeMax: 18, // 最高范围
|
|
|
};
|
|
|
},
|
|
|
+ watch: {
|
|
|
+ themeColor: {
|
|
|
+ handler(newVal, oldVal) {
|
|
|
+ if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
|
|
|
+ this.color1 = newVal;
|
|
|
+ this.updateChartColor();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ },
|
|
|
+ setUpImgData: {
|
|
|
+ handler(newVal, oldVal) {
|
|
|
+ if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
|
|
|
+ this.drawChart();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
mounted() {
|
|
|
- this.getData();
|
|
|
+ if (this.fileAddr) {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.getData();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState("themes", {
|
|
|
+ themeColor: "themeColor",
|
|
|
+ }),
|
|
|
},
|
|
|
methods: {
|
|
|
async getData() {
|
|
@@ -88,12 +150,16 @@ export default {
|
|
|
cancelToken: this.cancelToken.token,
|
|
|
});
|
|
|
this.chartData = resultChartsData.data;
|
|
|
+ this.color1 =
|
|
|
+ this.chartData.data.length >= 2
|
|
|
+ ? colorSchemes[0].colors
|
|
|
+ : "#588CF0";
|
|
|
// 使用 nextTick 来确保 DOM 渲染完成后绘制图表
|
|
|
nextTick(() => {
|
|
|
this.drawChart();
|
|
|
- this.isError = false;
|
|
|
- this.loading = false;
|
|
|
});
|
|
|
+ this.isError = false;
|
|
|
+ this.loading = false;
|
|
|
} catch (error) {
|
|
|
if (axios.isCancel(error)) {
|
|
|
console.warn("请求被取消:", error.message);
|
|
@@ -106,231 +172,73 @@ export default {
|
|
|
},
|
|
|
// 绘制图表
|
|
|
drawChart() {
|
|
|
- if (this.chartData.data && this.chartData.data.length === 0) return;
|
|
|
- const chartDataset = this.chartData.data[0];
|
|
|
- const trace = {
|
|
|
- x: chartDataset.xData, // 横坐标数据
|
|
|
- y: chartDataset.yData, // 纵坐标数据
|
|
|
- type: this.chartType, // 当前图表类型 ('bar' 或 'scatter')
|
|
|
- marker: {
|
|
|
- color: this.color1, // 柱状图颜色
|
|
|
- },
|
|
|
- line: {
|
|
|
- color: this.color1, // 折线图颜色
|
|
|
- },
|
|
|
- name: chartDataset.title || "数据", // 图例名称
|
|
|
- hovertemplate:
|
|
|
- `${this.chartData.xaixs}:` +
|
|
|
- ` %{x} <br> ` +
|
|
|
- `${this.chartData.yaixs}:` +
|
|
|
- "%{y} <br>",
|
|
|
- };
|
|
|
+ if (!this.chartData.data || this.chartData.data.length === 0) return;
|
|
|
+
|
|
|
+ const data = this.chartData.data.map((chartDataset, index) => {
|
|
|
+ return {
|
|
|
+ x: chartDataset.xData,
|
|
|
+ y: chartDataset.yData,
|
|
|
+ type: this.chartType, // 'bar' | 'scatter' | 'line'
|
|
|
+ name: chartDataset.title || `系列 ${index + 1}`,
|
|
|
+ marker: {
|
|
|
+ color:
|
|
|
+ this.chartData.data.length >= 2
|
|
|
+ ? colorSchemes[0].colors[colorSchemes[0].colors.length - index]
|
|
|
+ : "#588CF0", // 多颜色支持
|
|
|
+ },
|
|
|
+ line: {
|
|
|
+ color:
|
|
|
+ this.chartData.data.length >= 2
|
|
|
+ ? colorSchemes[0].colors[colorSchemes[0].colors.length - index]
|
|
|
+ : "#588CF0", // 多颜色支持
|
|
|
+ },
|
|
|
+ hovertemplate:
|
|
|
+ `${this.chartData.xaixs}: %{x}<br>` +
|
|
|
+ `${this.chartData.yaixs}: %{y}<br>`,
|
|
|
+ };
|
|
|
+ });
|
|
|
|
|
|
const layout = {
|
|
|
title: {
|
|
|
- text: chartDataset.title,
|
|
|
+ text: this.chartData.title || this.chartData.data[0].title,
|
|
|
font: {
|
|
|
- size: 16, // 设置标题字体大小(默认 16)
|
|
|
+ size: 16,
|
|
|
weight: "bold",
|
|
|
},
|
|
|
- }, // 图表标题
|
|
|
+ },
|
|
|
xaxis: {
|
|
|
- title: this.chartData.xaixs || "X轴", // 横坐标标题
|
|
|
+ title: this.chartData.xaixs || "X轴",
|
|
|
gridcolor: "rgb(255,255,255)",
|
|
|
- type: this.chartData.xaixs === "机组" ? "category" : undefined, // 让 Y 轴按类别均匀分布
|
|
|
+ type:
|
|
|
+ this.chartData.xaixs === "机组" ||
|
|
|
+ this.chartData.xaixs === "机组名称"
|
|
|
+ ? "category"
|
|
|
+ : undefined,
|
|
|
tickcolor: "rgb(255,255,255)",
|
|
|
- backgroundcolor: "#e5ecf6",
|
|
|
dtick: this.chartData.xaixs === "风速(m/s)" ? 1 : undefined,
|
|
|
},
|
|
|
yaxis: {
|
|
|
- title: this.chartData.yaixs || "Y轴", // 纵坐标标题
|
|
|
+ title: this.chartData.yaixs || "Y轴",
|
|
|
gridcolor: "rgb(255,255,255)",
|
|
|
tickcolor: "rgb(255,255,255)",
|
|
|
- backgroundcolor: "#e5ecf6",
|
|
|
- title_standoff: 100, // 设置标题与轴的距离
|
|
|
- },
|
|
|
- margin: {
|
|
|
- l: 50,
|
|
|
- r: 50,
|
|
|
- t: 50,
|
|
|
- b: 50,
|
|
|
},
|
|
|
plot_bgcolor: "#e5ecf6",
|
|
|
- gridcolor: "#fff",
|
|
|
- bgcolor: "#e5ecf6", // 设置背景颜色
|
|
|
- autosize: true, // 开启自适应
|
|
|
+ paper_bgcolor: "#e5ecf6",
|
|
|
+ barmode: "stack", // ✅ 堆叠模式
|
|
|
+ margin: { l: 50, r: 50, t: 50, b: 50 },
|
|
|
};
|
|
|
- // **如果 Y 轴是 "温度偏差",添加两条红色虚线**
|
|
|
- if (this.chartData.data[0].title === "温度偏差") {
|
|
|
- layout.shapes = [
|
|
|
- {
|
|
|
- type: "line",
|
|
|
- xref: "paper", // x 轴相对于整个图
|
|
|
- yref: "y",
|
|
|
- x0: 0,
|
|
|
- x1: 1, // 从左到右整个图表
|
|
|
- y0: 5,
|
|
|
- y1: 5,
|
|
|
- line: {
|
|
|
- color: "red",
|
|
|
- width: 2,
|
|
|
- dash: "dash", // 虚线
|
|
|
- },
|
|
|
- // ✅ 添加 hoverlabel
|
|
|
- hovertext: "上限: 5°C",
|
|
|
- hoverinfo: "text",
|
|
|
- },
|
|
|
- {
|
|
|
- type: "line",
|
|
|
- xref: "paper",
|
|
|
- yref: "y",
|
|
|
- x0: 0,
|
|
|
- x1: 1,
|
|
|
- y0: -5,
|
|
|
- y1: -5,
|
|
|
- line: {
|
|
|
- color: "red",
|
|
|
- width: 2,
|
|
|
- dash: "dash", // 虚线
|
|
|
- },
|
|
|
-
|
|
|
- hovertext: "下限: -5°C",
|
|
|
- hoverinfo: "text",
|
|
|
- },
|
|
|
- ];
|
|
|
- layout.hovermode = "x unified";
|
|
|
- }
|
|
|
- if (
|
|
|
- this.chartData.xaixs === "机组" ||
|
|
|
- this.chartData.xaixs === "机组名称"
|
|
|
- ) {
|
|
|
- layout.xaxis.tickvals = this.chartData.data[0].xData;
|
|
|
- layout.xaxis.ticktext = this.chartData.data[0].xData;
|
|
|
- }
|
|
|
-
|
|
|
- // 渲染图表
|
|
|
- Plotly.newPlot(
|
|
|
- `bar-chart-${this.inds}`,
|
|
|
-
|
|
|
- // [trace, normalRangeLine, normalRangeMaxLine],
|
|
|
- [trace],
|
|
|
- { ...layout },
|
|
|
- {
|
|
|
- displaylogo: false,
|
|
|
- responsive: true,
|
|
|
- modeBarButtonsToRemove: [
|
|
|
- // "pan2d", // 平移按钮
|
|
|
- "zoom2d", // 缩放按钮
|
|
|
- // "select2d", // 选择框
|
|
|
- // "lasso2d", // 套索选择
|
|
|
- // "resetScale2d", // 重置轴
|
|
|
- // // "zoomIn", // 放大
|
|
|
- // // "zoomOut", // 缩小
|
|
|
- // "home", // 重置
|
|
|
- // "toImage", // 导出为图片
|
|
|
- // "hoverClosestCartesian", // 悬浮信息
|
|
|
- // "zoomIn2d", // 缩放按钮(详细版本)
|
|
|
- // "zoomOut2d", // 缩放按钮(详细版本)
|
|
|
- // "autoScale2D",
|
|
|
- // "plotlylogo2D",
|
|
|
- // "Produced with Plotly.js(v2.35)", // 删除 Plotly logo
|
|
|
- ],
|
|
|
|
|
|
- // modeBarButtonsToAdd: [
|
|
|
- // {
|
|
|
- // name: "保存图片", // 直接写中文翻译
|
|
|
- // icon: Plotly.Icons["camera"],
|
|
|
- // click: function () {
|
|
|
- // console.log("选择框");
|
|
|
- // Plotly.downloadImage(gd, {
|
|
|
- // format: "png",
|
|
|
- // width: 800,
|
|
|
- // height: 600,
|
|
|
- // });
|
|
|
- // },
|
|
|
- // },
|
|
|
- // {
|
|
|
- // name: "选择框", // 直接写中文翻译
|
|
|
- // icon: Plotly.Icons["selectbox"],
|
|
|
- // click: function () {
|
|
|
- // console.log("选择框");
|
|
|
- // },
|
|
|
- // },
|
|
|
- // {
|
|
|
- // name: "套索选择", // 直接写中文翻译
|
|
|
- // icon: Plotly.Icons.lasso,
|
|
|
- // click: function () {
|
|
|
- // console.log("套索选择");
|
|
|
- // },
|
|
|
- // },
|
|
|
- // {
|
|
|
- // name: "放大", // 直接写中文翻译
|
|
|
- // icon: Plotly.Icons["zoom_plus"],
|
|
|
- // click: function () {
|
|
|
- // console.log("放大", Plotly.Icons);
|
|
|
- // },
|
|
|
- // },
|
|
|
- // {
|
|
|
- // name: "缩小", // 直接写中文翻译
|
|
|
- // icon: Plotly.Icons["zoom_minus"],
|
|
|
- // click: function () {
|
|
|
- // console.log("缩小", Plotly.Icons);
|
|
|
- // },
|
|
|
- // },
|
|
|
- // {
|
|
|
- // name: "缩放", // 直接写中文翻译
|
|
|
- // icon: Plotly.Icons["zoombox"],
|
|
|
- // click: function () {
|
|
|
- // console.log("缩放", Plotly.Icons);
|
|
|
- // },
|
|
|
- // },
|
|
|
- // {
|
|
|
- // name: "平移", // 直接写中文翻译
|
|
|
- // icon: Plotly.Icons.pan,
|
|
|
- // click: function () {
|
|
|
- // console.log("平移");
|
|
|
- // },
|
|
|
- // },
|
|
|
- // {
|
|
|
- // name: "还原", // 直接写中文翻译
|
|
|
- // icon: Plotly.Icons.home,
|
|
|
- // click: function () {
|
|
|
- // // 获取图表的 DOM 元素
|
|
|
- // var gd = document.getElementById(`bar-chart${this.inds}`);
|
|
|
- // Plotly.relayout(gd, {
|
|
|
- // "xaxis.range": null,
|
|
|
- // "yaxis.range": null,
|
|
|
- // });
|
|
|
- // },
|
|
|
- // },
|
|
|
- // ], // 这个必须是数组类型
|
|
|
- }
|
|
|
- ).then(function (gd) {
|
|
|
- // 获取工具栏按钮
|
|
|
- const toolbar = gd.querySelector(".modebar");
|
|
|
- const buttons = toolbar.querySelectorAll(".modebar-btn");
|
|
|
-
|
|
|
- // 定义一个映射对象,方便修改按钮提示
|
|
|
- const titleMap = {
|
|
|
- "Download plot as a png": "保存图片",
|
|
|
- Autoscale: "缩放",
|
|
|
- Pan: "平移",
|
|
|
- "Zoom out": "缩小",
|
|
|
- "Zoom in": "放大",
|
|
|
- "Box Select": "选择框操作",
|
|
|
- "Lasso Select": "套索选择操作",
|
|
|
- "Reset axes": "重置操作",
|
|
|
- };
|
|
|
-
|
|
|
- // 遍历所有按钮,修改它们的 title
|
|
|
- buttons.forEach(function (button) {
|
|
|
- const dataTitle = button.getAttribute("data-title");
|
|
|
-
|
|
|
- // 如果标题匹配,修改属性值
|
|
|
- if (titleMap[dataTitle]) {
|
|
|
- button.setAttribute("data-title", titleMap[dataTitle]);
|
|
|
- }
|
|
|
- });
|
|
|
+ Plotly.newPlot(`bar-chart-${this.inds}`, data, layout, {
|
|
|
+ responsive: true,
|
|
|
+ displaylogo: false,
|
|
|
+ modeBarButtonsToRemove: [
|
|
|
+ "zoom2d",
|
|
|
+ "zoomIn2d",
|
|
|
+ "zoomOut2d",
|
|
|
+ "autoScale2d",
|
|
|
+ "lasso2d",
|
|
|
+ "sendDataToCloud",
|
|
|
+ ],
|
|
|
});
|
|
|
},
|
|
|
// 切换图表类型
|
|
@@ -342,6 +250,23 @@ export default {
|
|
|
updateChartColor() {
|
|
|
this.drawChart();
|
|
|
},
|
|
|
+ // 根据配色方案设置每个选项的样式
|
|
|
+ getOptionStyle(scheme) {
|
|
|
+ return {
|
|
|
+ background: `linear-gradient(to right, ${scheme
|
|
|
+ .slice(0, 8)
|
|
|
+ .join(", ")})`,
|
|
|
+ color: "#fff",
|
|
|
+ height: "30px",
|
|
|
+ lineHeight: "30px",
|
|
|
+ borderRadius: "0px",
|
|
|
+ };
|
|
|
+ },
|
|
|
+ },
|
|
|
+ beforeUnmount() {
|
|
|
+ if (this.cancelToken) {
|
|
|
+ this.cancelToken.cancel("组件卸载,取消请求");
|
|
|
+ }
|
|
|
},
|
|
|
};
|
|
|
</script>
|