NoColourBandTwoDMarkerChart.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. <!--
  2. * @Author: your name
  3. * @Date: 2025-01-17 17:22:04
  4. * @LastEditTime: 2025-02-12 15:22:42
  5. * @LastEditors: bogon
  6. * @Description: In User Settings Edit
  7. * @FilePath: /performance-test/src/views/performance/components/chartsCom/NoColourBandTwoDMarkerChart.vue
  8. -->
  9. <template>
  10. <div style="height: 400px">
  11. <!-- 2D散点图 没色带 -->
  12. <template>
  13. <div style="display: flex; align-items: center; margin-top: 20px">
  14. <div style="margin-right: 20px; display: flex; align-items: center">
  15. <el-color-picker
  16. size="small"
  17. v-model="color1"
  18. show-alpha
  19. @change="updateChartColor"
  20. ></el-color-picker>
  21. <span style="margin-left: 10px">自定义颜色</span>
  22. </div>
  23. <!-- 图表类型切换按钮 -->
  24. <div>
  25. <el-button size="small" @click="setChartType('scatter')"
  26. >散点图</el-button
  27. >
  28. <el-button size="small" @click="setChartType('line')"
  29. >折线图</el-button
  30. >
  31. </div>
  32. </div>
  33. <div v-loading="loading" ref="plotlyChart" style="height: 400px">
  34. <el-empty v-if="isError" description="请求失败"></el-empty>
  35. </div>
  36. </template>
  37. </div>
  38. </template>
  39. <script>
  40. import Plotly from "plotly.js-dist";
  41. import axios from "axios";
  42. import { myMixin } from "@/mixins/chartRequestMixin";
  43. export default {
  44. mixins: [myMixin],
  45. props: {
  46. fileAddr: {
  47. default: "",
  48. type: String,
  49. },
  50. index: {
  51. type: String,
  52. },
  53. },
  54. data() {
  55. return {
  56. chartData: {},
  57. chartType: "scatter", // 初始化为散点图 (scatter)
  58. color1: "", // 默认颜色
  59. selectedPoints: [],
  60. originalColors: [],
  61. originalSizes: [],
  62. };
  63. },
  64. async mounted() {
  65. this.getData();
  66. },
  67. methods: {
  68. async getData() {
  69. if (this.fileAddr !== "") {
  70. try {
  71. this.loading = true;
  72. this.cancelToken = axios.CancelToken.source();
  73. console.log(this.cancelToken);
  74. const resultChartsData = await axios.get(this.fileAddr, {
  75. cancelToken: this.cancelToken.token,
  76. });
  77. this.chartData = resultChartsData.data;
  78. this.drawChart();
  79. this.isError = false;
  80. this.loading = false;
  81. } catch (error) {
  82. this.isError = true;
  83. this.loading = false;
  84. }
  85. }
  86. },
  87. drawChart() {
  88. const data = this.chartData.data && this.chartData.data[0];
  89. let trace = {};
  90. // 保存原始颜色和大小
  91. this.originalColors = [...data.yData];
  92. this.originalSizes = new Array(data.xData.length).fill(6); // 初始点大小
  93. if (this.chartType === "scatter") {
  94. // 绘制 2D 散点图
  95. console.log("重新绘制图表", this.color1);
  96. trace = {
  97. x: data.xData,
  98. y: data.yData,
  99. mode: "markers",
  100. type: "scattergl", // 这里改为 scattergl
  101. text: data.engineName, // 提示文本
  102. marker: {
  103. color: data.yData, // 根据 yData 的值设置颜色
  104. // colorscale: "Viridis", // 使用的颜色区间
  105. colorscale: this.color1
  106. ? [
  107. [0, "#F9FDD2"], // 颜色从 this.color1 开始
  108. [1, this.color1], // 结束颜色为其他颜色
  109. ]
  110. : [
  111. [0, "#F9FDD2"],
  112. [0.15, "#E9F6BD"],
  113. [0.3, "#C2E3B9"],
  114. [0.45, "#8AC8BE"],
  115. [0.6, "#5CA8BF"],
  116. [0.75, "#407DB3"],
  117. [0.9, "#2E4C9A"],
  118. [1, "#1B2973"],
  119. ],
  120. // colorbar: {
  121. // title: data.colorbartitle, // 色标标题
  122. // },
  123. size: new Array(data.xData.length).fill(6), // 初始点大小
  124. },
  125. };
  126. } else if (this.chartType === "line") {
  127. // 折线图
  128. trace = {
  129. x: data.xData,
  130. y: data.yData,
  131. mode: "lines",
  132. type: "scattergl", // 折线图
  133. text: data.engineName,
  134. line: {
  135. color: this.color1, // 使用自定义颜色
  136. },
  137. };
  138. } else if (this.chartType === "bar") {
  139. // 柱状图
  140. trace = {
  141. x: data.xData,
  142. y: data.yData,
  143. type: "bar", // 柱状图
  144. marker: {
  145. color: this.color1, // 使用自定义颜色
  146. },
  147. };
  148. }
  149. // 图表布局;
  150. const layout = {
  151. title: data.title,
  152. xaxis: {
  153. title: this.chartData.xaixs,
  154. showline: false, // 隐藏x轴轴线
  155. zeroline: false, // 隐藏零轴
  156. gridcolor: "#fff", // 设置x轴网格线颜色
  157. gridcolor: "rgb(255,255,255)", // 网格线颜色
  158. tickcolor: "rgb(255,255,255)",
  159. backgroundcolor: "#e5ecf6",
  160. showbackground: true, // 显示背景
  161. },
  162. yaxis: {
  163. showline: false, // 隐藏x轴轴线
  164. zeroline: false, // 隐藏零轴
  165. gridcolor: "#fff", // 设置x轴网格线颜色
  166. title: this.chartData.yaixs,
  167. line: {
  168. show: false,
  169. },
  170. gridcolor: "rgb(255,255,255)", // 网格线颜色
  171. tickcolor: "rgb(255,255,255)",
  172. backgroundcolor: "#e5ecf6",
  173. showbackground: true, // 显示背景
  174. },
  175. showlegend: false,
  176. plot_bgcolor: "#e5ecf6",
  177. gridcolor: "#fff", // 设置网格线颜色
  178. };
  179. const config = {
  180. modeBarButtonsToAdd: [
  181. {
  182. name: "选择",
  183. icon: Plotly.Icons.pencil,
  184. click: (gd) => this.handleSelectClick(gd),
  185. },
  186. {
  187. name: "清除选中",
  188. icon: Plotly.Icons.undo,
  189. click: (gd) => this.handleClearSelect(gd),
  190. },
  191. {
  192. name: "下载CSV文件",
  193. icon: Plotly.Icons.disk,
  194. click: (gd) => this.handleDownloadCSV(gd),
  195. },
  196. ],
  197. modeBarButtonsToRemove: [
  198. // 移除不需要的工具按钮
  199. "lasso2d",
  200. ],
  201. displaylogo: false,
  202. editable: true,
  203. scrollZoom: false,
  204. };
  205. // 使用 Plotly 绘制图表
  206. Plotly.react(this.$refs.plotlyChart, [trace], layout, config).then(() => {
  207. // 确保在图表加载完成后设置工具栏按钮
  208. const plotElement = this.$refs.plotlyChart;
  209. Plotly.relayout(plotElement, layout); // 使用 relayout 来确保自定义按钮应用
  210. });
  211. },
  212. handleSelectClick(gd) {
  213. // 绑定 plotly_click 事件
  214. gd.on("plotly_click", (data) => {
  215. const pointIndex = data.points[0].pointIndex;
  216. const xClick = data.points[0].x;
  217. const yClick = data.points[0].y;
  218. // 将点击的点添加到选中的点数组
  219. this.selectedPoints.push({
  220. x: xClick, // 点击点的 x 坐标
  221. y: yClick, // 点击点的 y 坐标
  222. index: pointIndex, // 点击点的索引
  223. time: data.points[0].text, // 点击点的时间信息
  224. });
  225. // 初始化颜色和大小数组
  226. let newColors = [...this.originalColors];
  227. let newSize = [...this.originalSizes];
  228. // 如果选中的点数大于等于3,进行多边形选择区域的处理
  229. if (this.selectedPoints.length >= 3) {
  230. const xv = this.selectedPoints.map((p) => p.x);
  231. const yv = this.selectedPoints.map((p) => p.y);
  232. // 判断点是否在多边形内
  233. function inPolygon(x, y, xv, yv) {
  234. let inside = false;
  235. for (let i = 0, j = xv.length - 1; i < xv.length; j = i++) {
  236. const intersect =
  237. yv[i] > y !== yv[j] > y &&
  238. x < ((xv[j] - xv[i]) * (y - yv[i])) / (yv[j] - yv[i]) + xv[i];
  239. if (intersect) inside = !inside;
  240. }
  241. return inside;
  242. }
  243. // 用于跟踪已添加的 (x, y) 组合
  244. const addedPoints = {};
  245. // 遍历图表数据中的所有点,检查是否在多边形内
  246. gd.data[0].x.forEach((xVal, i) => {
  247. const yVal = gd.data[0].y[i];
  248. if (inPolygon(xVal, yVal, xv, yv)) {
  249. const pointKey = `${xVal}-${yVal}`;
  250. if (!addedPoints[pointKey]) {
  251. this.selectedPoints.push({
  252. x: gd.data[0].x[i],
  253. y: gd.data[0].y[i],
  254. time: gd.data[0].text[i],
  255. });
  256. newColors[i] = "red"; // 高亮选择的点
  257. newSize[i] = 10; // 设置点的大小
  258. addedPoints[pointKey] = true;
  259. }
  260. }
  261. });
  262. }
  263. // 更新选中点的颜色和大小
  264. this.selectedPoints.forEach((point) => {
  265. newColors[point.index] = "red";
  266. newSize[point.index] = 10;
  267. });
  268. // 使用 Plotly.restyle 更新颜色和大小
  269. Plotly.restyle(gd, {
  270. "marker.color": [newColors],
  271. "marker.size": [newSize],
  272. });
  273. // 处理选中的数据
  274. this.getSelectData(this.selectedPoints, gd.layout);
  275. });
  276. },
  277. handleClearSelect(gd) {
  278. this.selectedPoints = [];
  279. Plotly.restyle(gd, {
  280. "marker.color": [this.originalColors],
  281. "marker.size": [this.originalSizes],
  282. });
  283. },
  284. getSelectData(selectedPoints, layout) {
  285. // 在这里处理选中的数据,您可以将其展示或导出等
  286. console.log("选中的点数据:", selectedPoints);
  287. console.log("布局信息:", layout);
  288. },
  289. handleDownloadCSV(gd) {
  290. if (this.selectedPoints.length === 0) {
  291. alert("没有选中的数据");
  292. return;
  293. }
  294. this.downloadCSV();
  295. },
  296. downloadCSV() {
  297. const headers = [this.chartData.xaixs, this.chartData.yaixs];
  298. const csvRows = [headers]; // 保存标头
  299. // 使用 Set 或 Map 去重
  300. const uniquePoints = [];
  301. this.selectedPoints.forEach((point) => {
  302. if (!uniquePoints.some((p) => p.x === point.x && p.y === point.y)) {
  303. uniquePoints.push(point);
  304. }
  305. });
  306. // 将去重后的点加入 CSV 数据
  307. uniquePoints.forEach((point) => {
  308. csvRows.push(`${point.x},${point.y}`);
  309. });
  310. const csvString = csvRows.join("\n");
  311. const blob = new Blob([csvString], { type: "text/csv; charset=utf-8" });
  312. const url = URL.createObjectURL(blob);
  313. const a = document.createElement("a");
  314. a.href = url;
  315. a.download = "selected_data.csv";
  316. a.click();
  317. URL.revokeObjectURL(url);
  318. },
  319. setChartType(type) {
  320. // 切换图表类型
  321. this.chartType = type;
  322. this.drawChart(); // 重新绘制图表
  323. },
  324. updateChartColor(color) {
  325. // 更新图表颜色
  326. this.color1 = color;
  327. console.log(this.color1, "this.color1");
  328. this.drawChart();
  329. },
  330. },
  331. };
  332. </script>
  333. <style scoped></style>