spectrogramcharts.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. <template>
  2. <div>
  3. <div class="FD">
  4. <!-- 光标 -->
  5. <div v-if="BGshow" class="eigenvalue">
  6. <el-checkbox-group v-model="checkedGB" @change="handlecursor">
  7. <el-checkbox v-for="(item, index) in GBcheckList" :key="index" :label="item.val" :disabled="item.disabled">
  8. {{ item.val }}
  9. </el-checkbox>
  10. </el-checkbox-group>
  11. </div>
  12. <!-- 特征值 -->
  13. <div v-if="PXshow" class="eigenvalue">
  14. <el-checkbox-group v-model="checkedValues" @change="handleCheckChange">
  15. <el-checkbox v-for="(item, index) in PXcheckList" :key="index" :label="item.val">
  16. {{ item.val }}
  17. </el-checkbox>
  18. </el-checkbox-group>
  19. </div>
  20. </div>
  21. <!-- ECharts 图表容器 -->
  22. <div class="line-chart" ref="chart"></div>
  23. </div>
  24. </template>
  25. <script>
  26. import axios from "axios";
  27. import * as echarts from "echarts";
  28. import cursorReferenceMixin from "./spectrogramcharts/cursorReferenceMixin";
  29. import Bdgb from "./spectrogramcharts/Bdgb";
  30. import Xdgb from "./spectrogramcharts/Xdgb";
  31. import Tjgb from "./spectrogramcharts/Tjgb";
  32. export default {
  33. name: "TimedomainCharts",
  34. mixins: [cursorReferenceMixin, Bdgb, Xdgb, Tjgb],
  35. props: {
  36. currentIndex: {
  37. type: Number,
  38. default: 0,
  39. },
  40. activeIndex: {
  41. type: Number,
  42. default: 0,
  43. },
  44. ids: {
  45. type: Array,
  46. default: () => [],
  47. },
  48. spectrumListTwo: {
  49. type: Object,
  50. default: () => ({}),
  51. },
  52. currentRow: {
  53. type: Object,
  54. default: () => ({}),
  55. },
  56. windCode: {
  57. type: String,
  58. default: "",
  59. },
  60. },
  61. data() {
  62. return {
  63. chartInstance: null,
  64. option: null,
  65. // TZshow: false,
  66. BGshow: false,
  67. PXshow: false,
  68. spectrumList: {},
  69. GBcheckList: [
  70. { val: "添加光标", checked: false, disabled: false },
  71. { val: "谐波光标", checked: false, disabled: false },
  72. { val: "边带光标", checked: false, disabled: false },
  73. { val: "移动峰值", checked: false, disabled: false },
  74. ],
  75. PXcheckList: [
  76. { val: "Fr", checked: false },
  77. { val: "BPFI", checked: false },
  78. { val: "BPFO", checked: false },
  79. { val: "BSF", checked: false },
  80. { val: "FTF", checked: false },
  81. { val: "3P", checked: false },
  82. ],
  83. Fr: [],
  84. BPFI: [],
  85. BPFO: [],
  86. BSF: [],
  87. FTF: [],
  88. B3P: [],
  89. checkedGB: [],
  90. checkedValues: [],
  91. };
  92. },
  93. watch: {
  94. spectrumListTwo(newValue) {
  95. this.spectrumList = newValue;
  96. if (this.chartInstance) {
  97. this.updateChart(this.spectrumList.y, this.spectrumList.x);
  98. }
  99. },
  100. spectrumList: {
  101. handler(newValue) {
  102. if (!newValue) return;
  103. if (this.chartInstance) {
  104. this.updateChart(newValue.y, newValue.x);
  105. }
  106. },
  107. deep: true,
  108. },
  109. },
  110. beforeDestroy() {
  111. if (this.chartInstance) {
  112. this.chartInstance.getZr().off("dblclick", this.handleDoubleClick);
  113. this.chartInstance
  114. .getZr()
  115. .off("mousemove", this.handleSidebandCursorMove);
  116. this.chartInstance.dispose();
  117. }
  118. },
  119. mounted() {
  120. this.$nextTick(() => {
  121. setTimeout(() => {
  122. this.initializeChart();
  123. this.getTime();
  124. }, 500);
  125. });
  126. },
  127. methods: {
  128. initializeChart() {
  129. const chartDom = this.$refs.chart;
  130. if (chartDom && !this.chartInstance) {
  131. this.chartInstance = echarts.init(chartDom);
  132. this.chartInstance.getZr().on("dblclick", this.handleDoubleClick);
  133. }
  134. this.$nextTick(() => {
  135. if (this.chartInstance && this.spectrumList.y && this.spectrumList.x) {
  136. this.updateChart(this.spectrumList.y, this.spectrumList.x);
  137. }
  138. });
  139. },
  140. // 光标
  141. handlecursor() {
  142. // 特殊光标类型数组
  143. const specialCursors = ["添加光标","移动峰值", "边带光标", "谐波光标"];
  144. // 检查是否有多个特殊光标被选中
  145. const selectedSpecials = specialCursors.filter((type) =>
  146. this.checkedGB.includes(type)
  147. );
  148. // 如果多于1个,则只保留第一个
  149. if (selectedSpecials.length > 1) {
  150. this.checkedGB = [
  151. ...this.checkedGB.filter((val) => !specialCursors.includes(val)),
  152. selectedSpecials[0], // 保留第一个选中的
  153. ];
  154. }
  155. // 其余逻辑保持不变...
  156. const isMoveChecked = this.checkedGB.includes("移动峰值");
  157. const isSidebandChecked = this.checkedGB.includes("边带光标");
  158. const isHarmonicChecked = this.checkedGB.includes("谐波光标");
  159. isMoveChecked ? this.handleMoveCursor() : this.removeCursor();
  160. isSidebandChecked
  161. ? this.enableSidebandCursor()
  162. : this.disableSidebandCursor();
  163. isHarmonicChecked
  164. ? this.enableHarmonicCursor()
  165. : this.disableHarmonicCursor();
  166. // 设置互斥disabled状态
  167. this.GBcheckList = this.GBcheckList.map((item) => ({
  168. ...item,
  169. disabled:
  170. specialCursors.includes(item.val) &&
  171. this.checkedGB.some(
  172. (val) => val !== item.val && specialCursors.includes(val)
  173. ),
  174. }));
  175. },
  176. // 特征值
  177. handleCheckChange() {
  178. this.PXcheckList.forEach((item) => {
  179. item.checked = this.checkedValues.includes(item.val);
  180. });
  181. this.updateFeatureLines();
  182. },
  183. updateFeatureLines() {
  184. const newFeatureLines = {
  185. Fr: this.checkedValues.includes("Fr") ? this.spectrumList.fn_Gen : [],
  186. BPFI: this.checkedValues.includes("BPFI") ? this.spectrumList.BPFI : [],
  187. BPFO: this.checkedValues.includes("BPFO") ? this.spectrumList.BPFO : [],
  188. BSF: this.checkedValues.includes("BSF") ? this.spectrumList.BSF : [],
  189. FTF: this.checkedValues.includes("FTF") ? this.spectrumList.FTF : [],
  190. B3P: this.checkedValues.includes("3P")
  191. ? Array.isArray(this.spectrumList.B3P)
  192. ? this.spectrumList.B3P
  193. : [{ Xaxis: this.spectrumList.B3P, val: "3P" }]
  194. : [],
  195. };
  196. if (this.chartInstance) {
  197. const currentOption = this.chartInstance.getOption();
  198. // 获取现有的光标系列
  199. const cursorLineSeries =
  200. currentOption.series.find((s) => s.id === "CURSOR_LINE_SERIES") || {};
  201. const cursorPointSeries =
  202. currentOption.series.find((s) => s.id === "CURSOR_POINT_SERIES") ||
  203. {};
  204. const cursorHighLineSeries =
  205. currentOption.series.find((s) => s.id === "PEAK_REFERENCE_LINE") ||
  206. {};
  207. // 生成新的特征值系列
  208. const featureSeries = this.generateSeries(newFeatureLines);
  209. this.chartInstance.setOption(
  210. {
  211. series: [
  212. currentOption.series[0], // 主数据系列
  213. ...featureSeries.slice(1), // 新的特征值系列
  214. cursorLineSeries, // 保留光标线系列
  215. cursorPointSeries, // 保留光标点系列
  216. cursorHighLineSeries, // 保留峰值参考线
  217. ],
  218. },
  219. { replaceMerge: ["series"] }
  220. );
  221. }
  222. },
  223. generateSeries(featureLines) {
  224. const createMarkLine = (dataSource, color) => ({
  225. type: "line",
  226. markLine: {
  227. silent: false,
  228. lineStyle: { color, type: "dashed", width: 1 },
  229. symbol: ["arrow", "none"],
  230. label: {
  231. show: true,
  232. position: "end",
  233. formatter: ({ data }) => data.val,
  234. },
  235. emphasis: {
  236. lineStyle: { color: "#FF6A00", width: 2 },
  237. label: {
  238. show: true,
  239. formatter: ({ value }) => `特征值: ${value}`,
  240. color: "#000",
  241. },
  242. },
  243. data: dataSource.map(({ Xaxis, val }) => ({ xAxis: Xaxis, val })),
  244. },
  245. });
  246. const markLines = [
  247. { data: featureLines.Fr, color: "#A633FF" },
  248. { data: featureLines.BPFI, color: "#23357e" },
  249. { data: featureLines.BPFO, color: "#42a0ae" },
  250. { data: featureLines.BSF, color: "#008080" },
  251. { data: featureLines.FTF, color: "#af254f" },
  252. { data: featureLines.B3P, color: "#FFD700" },
  253. ].map(({ data, color }) => createMarkLine(data, color));
  254. return [
  255. {
  256. name: "数据系列",
  257. type: "line",
  258. data: this.spectrumList.x.map((x, i) => [x, this.spectrumList.y[i]]),
  259. symbol: "none",
  260. lineStyle: { color: "#162961", width: 1 },
  261. itemStyle: { color: "#162961", borderColor: "#fff", borderWidth: 1 },
  262. large: true,
  263. },
  264. ...markLines,
  265. ];
  266. },
  267. updateChart(data, labels) {
  268. if (
  269. !this.chartInstance ||
  270. !Array.isArray(labels) ||
  271. !Array.isArray(data) ||
  272. labels.length !== data.length
  273. ) {
  274. console.error("Invalid data or labels");
  275. return;
  276. }
  277. const createMarkLine = (dataSource, color) => ({
  278. type: "line",
  279. markLine: {
  280. silent: false,
  281. lineStyle: { color, type: "solid", width: 2 },
  282. symbol: ["arrow", "none"],
  283. label: {
  284. show: true,
  285. position: "end",
  286. formatter: ({ data }) => data.val,
  287. },
  288. emphasis: {
  289. lineStyle: { color: "#FF6A00", width: 4 },
  290. label: {
  291. show: true,
  292. formatter: ({ value }) => `特征值: ${value}`,
  293. color: "#000",
  294. backgroundColor: "#FFF",
  295. padding: [2, 4],
  296. borderRadius: 3,
  297. fontSize: 12,
  298. },
  299. },
  300. data: dataSource.map(({ Xaxis, val }) => ({ xAxis: Xaxis, val })),
  301. },
  302. });
  303. const markLines = [
  304. { data: this.Fr, color: "#A633FF" },
  305. { data: this.BPFI, color: "#23357e" },
  306. { data: this.BPFO, color: "#42a0ae" },
  307. { data: this.BSF, color: "#008080" },
  308. { data: this.FTF, color: "#af254f" },
  309. { data: this.B3P, color: "#FFD700" },
  310. ].map(({ data, color }) => createMarkLine(data, color));
  311. const option = {
  312. title: { text: this.spectrumList.title, left: "center" },
  313. toolbox: {
  314. feature: {
  315. dataZoom: { yAxisIndex: "none" },
  316. restore: {},
  317. saveAsImage: {},
  318. myCustomTool: {
  319. show: true,
  320. title: "上一条",
  321. icon: `image://${require("@/assets/analyse/08.png")}`,
  322. onclick: () => this.previousRow(),
  323. },
  324. myCustomTool2: {
  325. show: true,
  326. title: "下一条",
  327. icon: `image://${require("@/assets/analyse/09.png")}`,
  328. onclick: () => this.nextRow(),
  329. },
  330. myCustomTool4: {
  331. show: true,
  332. title: "光标",
  333. icon: `image://${require("@/assets/analyse/12.png")}`,
  334. onclick: () => this.Show("2"),
  335. },
  336. myCustomTool5: {
  337. show: true,
  338. title: "特征频率",
  339. icon: `image://${require("@/assets/analyse/13.png")}`,
  340. onclick: () => this.Show("3"),
  341. },
  342. },
  343. },
  344. xAxis: {
  345. type: "value",
  346. name: this.spectrumList.xaxis,
  347. nameLocation: "center",
  348. nameTextStyle: {
  349. fontSize: 14,
  350. color: "#333",
  351. padding: [10, 0, 0, 0],
  352. },
  353. },
  354. yAxis: {
  355. type: "value",
  356. name: this.spectrumList.yaxis,
  357. nameTextStyle: {
  358. fontSize: 14,
  359. color: "#333",
  360. padding: [10, 0, 0, 0],
  361. },
  362. },
  363. tooltip: {
  364. trigger: "axis",
  365. formatter: ([
  366. {
  367. value: [x, y],
  368. },
  369. ]) => `X: ${x}<br/>Y: ${y}`,
  370. axisPointer: { type: "line" },
  371. },
  372. dataZoom: [
  373. { type: "inside", start: 0, end: 10 },
  374. {
  375. type: "slider",
  376. start: 0,
  377. end: 10,
  378. handleSize: "80%",
  379. showDataShadow: false,
  380. },
  381. ],
  382. series: [
  383. {
  384. name: "数据系列",
  385. type: "line",
  386. data: labels.map((x, i) => [x, data[i]]),
  387. symbol: "none",
  388. lineStyle: { color: "#162961", width: 1 },
  389. itemStyle: {
  390. color: "#162961",
  391. borderColor: "#fff",
  392. borderWidth: 1,
  393. },
  394. large: true,
  395. progressive: 2000,
  396. },
  397. ...markLines,
  398. ],
  399. };
  400. this.chartInstance.setOption(option);
  401. },
  402. // 获取数据
  403. getTime() {
  404. this.$emit("handleLoading", null, true, this.activeIndex);
  405. const params = {
  406. ids: this.ids,
  407. windCode: this.windCode,
  408. analysisType: "frequency",
  409. };
  410. axios
  411. .post("/WJapi/analysis/frequency", params)
  412. .then((res) => {
  413. this.spectrumList = { ...JSON.parse(res.data) };
  414. console.log(this.spectrumList, "频谱图数据1");
  415. const XrmsValue = this.spectrumList?.Xrms;
  416. this.$emit("updateXrms", XrmsValue);
  417. this.PXcheckList.forEach((item) => {
  418. if (item.checked) {
  419. switch (item.val) {
  420. case "Fr":
  421. this.Fr = this.spectrumList.fn_Gen;
  422. break;
  423. case "BPFI":
  424. this.BPFI = this.spectrumList.BPFI;
  425. break;
  426. case "BPFO":
  427. this.BPFO = this.spectrumList.BPFO;
  428. break;
  429. case "BSF":
  430. this.BSF = this.spectrumList.BSF;
  431. break;
  432. case "FTF":
  433. this.FTF = this.spectrumList.FTF;
  434. break;
  435. case "3P":
  436. this.B3P = Array.isArray(this.spectrumList.B3P)
  437. ? this.spectrumList.B3P
  438. : [{ Xaxis: this.spectrumList.B3P, val: "3P" }];
  439. break;
  440. default:
  441. break;
  442. }
  443. }
  444. });
  445. })
  446. .catch((error) => {
  447. console.error(error);
  448. })
  449. .finally(() => {
  450. this.$emit("handleLoading", this.currentRow, false, this.activeIndex);
  451. });
  452. },
  453. previousRow() {
  454. this.$emit("update-previous-row", 2, this.activeIndex);
  455. },
  456. nextRow() {
  457. this.$emit("update-next-row", 2, this.activeIndex);
  458. },
  459. Show(value) {
  460. const stateMap = {
  461. 1: { TZshow: true, BGshow: false, PXshow: false },
  462. 2: { TZshow: false, BGshow: true, PXshow: false },
  463. 3: { TZshow: false, BGshow: false, PXshow: true },
  464. };
  465. if (stateMap[value]) {
  466. this.TZshow = value === "1" ? !this.TZshow : false;
  467. this.BGshow = value === "2" ? !this.BGshow : false;
  468. this.PXshow = value === "3" ? !this.PXshow : false;
  469. }
  470. },
  471. },
  472. };
  473. </script>
  474. <style lang="scss" scoped>
  475. .line-chart {
  476. width: 100%;
  477. height: 280px;
  478. }
  479. .FD {
  480. width: 100%;
  481. height: 1px;
  482. position: relative;
  483. }
  484. .eigenvalue {
  485. position: absolute;
  486. top: 30px;
  487. right: 0;
  488. font-size: 10px;
  489. width: 100px;
  490. border: 1px solid black;
  491. padding: 5px;
  492. background: #fff;
  493. z-index: 99;
  494. h5 {
  495. line-height: 16px;
  496. height: 16px;
  497. }
  498. }
  499. </style>