widgetLineCompareChart.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. <template>
  2. <div :style="styleObj">
  3. <v-chart ref="myVChart" :options="options" autoresize />
  4. </div>
  5. </template>
  6. <script>
  7. import {targetWidgetLinkageLogic} from "@/views/bigscreenDesigner/designer/linkageLogic";
  8. export default {
  9. name: "WidgetBarCompareChart",
  10. //参考 https://www.makeapie.com/editor.html?c=xOjLyozu2W
  11. components: {},
  12. props: {
  13. value: Object,
  14. ispreview: Boolean,
  15. },
  16. data() {
  17. return {
  18. options: {
  19. axisPointer: {
  20. link: {
  21. xAxisIndex: "all",
  22. },
  23. },
  24. title: {
  25. x: "center",
  26. textStyle: {
  27. color: "#ffffff",
  28. },
  29. },
  30. tooltip: {
  31. show: true,
  32. trigger: "axis",
  33. axisPointer: {
  34. type: "line",
  35. lineStyle: {
  36. color: "#ffffff",
  37. type: "dashed",
  38. },
  39. },
  40. /*axisPointer: {
  41. type: 'cross',
  42. lineStyle: {
  43. color: '#ffffff',
  44. type: 'dashed',
  45. },
  46. crossStyle: {
  47. color: '#ffffff',
  48. }
  49. },*/
  50. },
  51. //边距
  52. grid: [
  53. {
  54. // 上
  55. left: 30,
  56. right: 20,
  57. top: "60px",
  58. containLabel: true,
  59. bottom: "50%",
  60. },
  61. {
  62. // 下
  63. left: 30,
  64. containLabel: true,
  65. right: 20,
  66. top: "51%",
  67. },
  68. ],
  69. //图例
  70. legend: {
  71. textStyle: {
  72. color: "#fff",
  73. textAlign: "center",
  74. },
  75. //itemGap:80,
  76. //itemWidth: 0
  77. },
  78. xAxis: [
  79. {
  80. //
  81. gridIndex: 0,
  82. show: true,
  83. type: "category",
  84. boundaryGap: true, // 居中
  85. axisLine: {
  86. //x轴线
  87. show: true,
  88. lineStyle: {
  89. color: "#ffffff",
  90. },
  91. },
  92. axisTick: {
  93. // 刻度
  94. show: true,
  95. },
  96. axisLabel: {
  97. // X轴数据
  98. show: true,
  99. textStyle: {
  100. interval: 0,
  101. color: "#ffffff",
  102. fontSize: 14,
  103. },
  104. },
  105. data: [],
  106. },
  107. {
  108. //
  109. gridIndex: 1,
  110. show: true,
  111. type: "category",
  112. position: "top",
  113. boundaryGap: true, // 居中
  114. axisLine: {
  115. // x轴线
  116. show: true,
  117. lineStyle: {
  118. color: "#ffffff",
  119. },
  120. },
  121. axisTick: {
  122. // 刻度
  123. show: true,
  124. },
  125. axisLabel: {
  126. show: false,
  127. interval: 0,
  128. },
  129. data: [],
  130. },
  131. ],
  132. yAxis: [
  133. {
  134. gridIndex: 0,
  135. show: true,
  136. scale: true, // 是否不从0开始,false从0开始
  137. axisLabel: {
  138. show: true,
  139. textStyle: {
  140. color: "#ffffff",
  141. fontSize: 14,
  142. },
  143. },
  144. axisLine: {
  145. // 轴线
  146. show: true,
  147. lineStyle: {
  148. color: "#ffffff",
  149. },
  150. },
  151. splitLine: {
  152. show: false,
  153. lineStyle: {
  154. color: "#ffffff",
  155. },
  156. },
  157. axisPointer: {
  158. snap: true,
  159. },
  160. },
  161. {
  162. gridIndex: 1,
  163. scale: false, // 是否从0开始
  164. inverse: true, // 翻转
  165. axisLabel: {
  166. show: true,
  167. textStyle: {
  168. color: "#ffffff",
  169. fontSize: 14,
  170. },
  171. },
  172. axisLine: {
  173. // 轴线
  174. show: true,
  175. lineStyle: {
  176. color: "#ffffff",
  177. },
  178. },
  179. splitLine: {
  180. show: false,
  181. lineStyle: {
  182. color: "#ffffff",
  183. },
  184. },
  185. axisPointer: {
  186. snap: true,
  187. },
  188. },
  189. ],
  190. series: [
  191. {
  192. name: "",
  193. type: "line",
  194. xAxisIndex: 0,
  195. yAxisIndex: 0,
  196. showSymbol: true, // 标记点
  197. symbol: "circle",
  198. symbolSize: 5,
  199. smooth: true, // 曲线,折线
  200. itemStyle: {
  201. color: "#36c5e7",
  202. },
  203. lineStyle: {
  204. color: "#36c5e7",
  205. width: 2,
  206. },
  207. label: {
  208. // 数值
  209. position: "top",
  210. distance: 10,
  211. show: true,
  212. color: "#36c5e7",
  213. fontSize: 14,
  214. },
  215. data: [],
  216. },
  217. {
  218. name: "",
  219. type: "line",
  220. xAxisIndex: 1,
  221. yAxisIndex: 1,
  222. showSymbol: true, // 标记点
  223. symbol: "circle",
  224. symbolSize: 5,
  225. smooth: true, // 曲线,折线
  226. itemStyle: {
  227. color: "#e68b55",
  228. },
  229. lineStyle: {
  230. color: "#e68b55",
  231. width: 2,
  232. },
  233. label: {
  234. // 数值
  235. position: "bottom",
  236. distance: 10,
  237. show: true,
  238. color: "#e68b55",
  239. fontSize: 16,
  240. },
  241. data: [],
  242. },
  243. ],
  244. },
  245. optionsStyle: {},
  246. optionsData: {},
  247. optionsSetup: {},
  248. flagInter: null,
  249. };
  250. },
  251. computed: {
  252. styleObj() {
  253. return {
  254. position: this.ispreview ? "absolute" : "static",
  255. width: this.optionsStyle.width + "px",
  256. height: this.optionsStyle.height + "px",
  257. left: this.optionsStyle.left + "px",
  258. top: this.optionsStyle.top + "px",
  259. background: this.optionsSetup.background,
  260. };
  261. },
  262. allComponentLinkage() {
  263. return this.$store.state.designer.allComponentLinkage;
  264. },
  265. },
  266. watch: {
  267. value: {
  268. handler(val) {
  269. this.optionsStyle = val.position;
  270. this.optionsData = val.data;
  271. this.optionsCollapse = val.setup;
  272. this.optionsSetup = val.setup;
  273. this.editorOptions();
  274. },
  275. deep: true,
  276. },
  277. },
  278. mounted() {
  279. this.optionsStyle = this.value.position;
  280. this.optionsData = this.value.data;
  281. this.optionsCollapse = this.value.setup;
  282. this.optionsSetup = this.value.setup;
  283. this.editorOptions();
  284. targetWidgetLinkageLogic(this); // 联动-目标组件逻辑
  285. },
  286. methods: {
  287. // 修改图标options属性
  288. editorOptions() {
  289. this.setOptionsTitle();
  290. this.setOptionsX();
  291. this.setOptionsYTop();
  292. this.setOptionsYBottom();
  293. this.setOptionsTop();
  294. this.setOptionsTooltip();
  295. this.setOptionsGrid();
  296. this.setOptionsLegend();
  297. this.setOptionsColor();
  298. this.setOptionsData();
  299. },
  300. // 标题修改
  301. setOptionsTitle() {
  302. const optionsSetup = this.optionsSetup;
  303. const title = {};
  304. title.text = optionsSetup.titleText;
  305. title.show = optionsSetup.isNoTitle;
  306. title.left = optionsSetup.textAlign;
  307. title.textStyle = {
  308. color: optionsSetup.textColor,
  309. fontSize: optionsSetup.textFontSize,
  310. fontWeight: optionsSetup.textFontWeight,
  311. fontStyle: optionsSetup.textFontStyle,
  312. };
  313. title.subtext = optionsSetup.subText;
  314. title.subtextStyle = {
  315. color: optionsSetup.subTextColor,
  316. fontWeight: optionsSetup.subTextFontWeight,
  317. fontSize: optionsSetup.subTextFontSize,
  318. fontStyle: optionsSetup.subTextFontStyle,
  319. };
  320. this.options.title = title;
  321. },
  322. // X轴设置
  323. setOptionsX() {
  324. const optionsSetup = this.optionsSetup;
  325. const xAxis0 = {
  326. gridIndex: 0,
  327. show: optionsSetup.isShowX,
  328. name: optionsSetup.nameX, // 坐标轴名称
  329. nameTextStyle: {
  330. color: optionsSetup.nameColorX,
  331. fontSize: optionsSetup.nameFontSizeX,
  332. },
  333. type: "category",
  334. boundaryGap: optionsSetup.boundaryX, // 值居中
  335. axisLine: {
  336. //x轴线
  337. show: optionsSetup.lineX,
  338. lineStyle: {
  339. color: optionsSetup.lineColorX,
  340. },
  341. },
  342. axisTick: {
  343. // 刻度
  344. show: optionsSetup.tickLineX,
  345. },
  346. axisLabel: {
  347. // X轴数据
  348. show: true,
  349. interval: optionsSetup.splitNumberX,
  350. textStyle: {
  351. color: optionsSetup.colorX,
  352. fontSize: optionsSetup.fontSizeX,
  353. },
  354. },
  355. };
  356. const xAxis1 = {
  357. gridIndex: 1,
  358. show: optionsSetup.isShowX,
  359. type: "category",
  360. position: "top",
  361. boundaryGap: optionsSetup.boundaryX, // 值居中
  362. axisLine: {
  363. // x轴线
  364. show: optionsSetup.lineX,
  365. lineStyle: {
  366. color: optionsSetup.lineColorX,
  367. },
  368. },
  369. axisTick: {
  370. // 刻度
  371. show: optionsSetup.tickLineX,
  372. },
  373. axisLabel: {
  374. show: false,
  375. interval: optionsSetup.splitNumberX,
  376. },
  377. };
  378. this.options.xAxis[0] = xAxis0;
  379. this.options.xAxis[1] = xAxis1;
  380. },
  381. // 上y轴设置
  382. setOptionsYTop() {
  383. const optionsSetup = this.optionsSetup;
  384. const yAxis = {
  385. gridIndex: 0,
  386. splitNumber: optionsSetup.splitNumberYTop,
  387. show: optionsSetup.isShowYTop,
  388. scale: optionsSetup.scaleYTop, // 缩放
  389. name: optionsSetup.textNameY, // 坐标轴名称
  390. nameTextStyle: {
  391. color: optionsSetup.nameColorY,
  392. fontSize: optionsSetup.nameFontSizeY,
  393. },
  394. axisLabel: {
  395. show: true,
  396. textStyle: {
  397. color: optionsSetup.colorYTop,
  398. fontSize: optionsSetup.fontSizeYTop,
  399. },
  400. },
  401. axisTick: {
  402. // 刻度
  403. show: optionsSetup.tickLineYTop,
  404. },
  405. axisLine: {
  406. // 轴线
  407. show: optionsSetup.lineYTop,
  408. lineStyle: {
  409. color: optionsSetup.lineColorYTop,
  410. },
  411. },
  412. splitLine: {
  413. show: optionsSetup.splitLineYTop,
  414. lineStyle: {
  415. width: optionsSetup.splitLineFontWidthYTop,
  416. color: optionsSetup.splitLineColorYTop,
  417. },
  418. },
  419. axisPointer: {
  420. snap: true,
  421. },
  422. };
  423. this.options.yAxis[0] = yAxis;
  424. },
  425. // 下Y轴设置
  426. setOptionsYBottom() {
  427. const optionsSetup = this.optionsSetup;
  428. const yAxis = {
  429. gridIndex: 1,
  430. splitNumber: optionsSetup.splitNumberYBottom,
  431. show: optionsSetup.isShowYBottom,
  432. scale: optionsSetup.scaleYBottom, // 缩放
  433. name: optionsSetup.textNameY, // 坐标轴名称
  434. nameTextStyle: {
  435. color: optionsSetup.nameColorY,
  436. fontSize: optionsSetup.nameFontSizeY,
  437. },
  438. inverse: true, // 翻转
  439. axisLabel: {
  440. show: true,
  441. textStyle: {
  442. color: optionsSetup.colorYBottom,
  443. fontSize: optionsSetup.fontSizeYBottom,
  444. },
  445. },
  446. axisTick: {
  447. // 刻度
  448. show: optionsSetup.tickLineYBottom,
  449. },
  450. axisLine: {
  451. // 轴线
  452. show: optionsSetup.lineYBottom,
  453. lineStyle: {
  454. color: optionsSetup.lineColorYBottom,
  455. },
  456. },
  457. splitLine: {
  458. show: optionsSetup.splitLineYBottom,
  459. lineStyle: {
  460. width: optionsSetup.splitLineFontWidthYBottom,
  461. color: optionsSetup.splitLineColorYBottom,
  462. },
  463. },
  464. axisPointer: {
  465. snap: true,
  466. },
  467. };
  468. this.options.yAxis[1] = yAxis;
  469. },
  470. // 数值设定 折线设置
  471. setOptionsTop() {
  472. const optionsSetup = this.optionsSetup;
  473. const series = this.options.series;
  474. // 折线
  475. for (const key in series) {
  476. series[key].symbol = optionsSetup.symbol;
  477. series[key].showSymbol = optionsSetup.markPoint;
  478. series[key].symbolSize = optionsSetup.pointSize;
  479. series[key].smooth = optionsSetup.smoothCurve;
  480. if (optionsSetup.area) {
  481. series[key].areaStyle = {
  482. opacity: optionsSetup.areaThickness / 100,
  483. };
  484. } else {
  485. series[key].areaStyle = {
  486. opacity: 0,
  487. };
  488. }
  489. }
  490. // 数值
  491. if (series[0].type == "line") {
  492. series[0].label = {
  493. position: "top",
  494. distance: 10,
  495. show: optionsSetup.isShow,
  496. color: optionsSetup.dataColor,
  497. fontSize: optionsSetup.fontSize,
  498. fontWeight: optionsSetup.fontWeight,
  499. };
  500. series[1].label = {
  501. position: "bottom",
  502. distance: 10,
  503. show: optionsSetup.isShow,
  504. color: optionsSetup.dataColor,
  505. fontSize: optionsSetup.fontSize,
  506. fontWeight: optionsSetup.fontWeight,
  507. };
  508. }
  509. },
  510. // tooltip 提示语设置
  511. setOptionsTooltip() {
  512. const optionsSetup = this.optionsSetup;
  513. let tooltip = {};
  514. if (optionsSetup.tipsType == "line") {
  515. tooltip = {
  516. show: optionsSetup.tipsShow,
  517. trigger: "axis",
  518. axisPointer: {
  519. type: optionsSetup.tipsType,
  520. lineStyle: {
  521. color: optionsSetup.tipsColor,
  522. type: "dashed",
  523. },
  524. },
  525. };
  526. } else {
  527. tooltip = {
  528. show: optionsSetup.tipsShow,
  529. trigger: "axis",
  530. axisPointer: {
  531. type: optionsSetup.tipsType,
  532. lineStyle: {
  533. color: optionsSetup.tipsColor,
  534. type: "dashed",
  535. },
  536. crossStyle: {
  537. color: optionsSetup.tipsColor,
  538. },
  539. },
  540. };
  541. }
  542. this.options.tooltip = tooltip;
  543. },
  544. // 边距设置
  545. setOptionsGrid() {
  546. const optionsSetup = this.optionsSetup;
  547. const grid = [
  548. {
  549. // 上
  550. left: optionsSetup.marginLeft,
  551. right: optionsSetup.marginRight,
  552. top: optionsSetup.marginTop,
  553. containLabel: true,
  554. bottom: "50%",
  555. },
  556. {
  557. // 下
  558. left: optionsSetup.marginLeft,
  559. right: optionsSetup.marginRight,
  560. containLabel: true,
  561. top: "51%",
  562. bottom: optionsSetup.marginBottom,
  563. },
  564. ];
  565. this.options.grid = grid;
  566. },
  567. // 图例操作
  568. setOptionsLegend() {
  569. const optionsSetup = this.optionsSetup;
  570. const legend = this.options.legend;
  571. legend.show = optionsSetup.isShowLegend;
  572. legend.left = optionsSetup.lateralPosition;
  573. legend.top = optionsSetup.longitudinalPosition;
  574. legend.bottom = optionsSetup.longitudinalPosition;
  575. legend.orient = optionsSetup.layoutFront;
  576. legend.textStyle = {
  577. color: optionsSetup.legendColor,
  578. fontSize: optionsSetup.legendFontSize,
  579. };
  580. legend.itemWidth = optionsSetup.legendWidth;
  581. },
  582. // 图例名称设置
  583. setOptionsLegendName(name) {
  584. const optionsSetup = this.optionsSetup;
  585. const series = this.options.series;
  586. const legendName = optionsSetup.legendName;
  587. // 图例没有手动写则显示原值,写了则显示新值
  588. if (null == legendName || legendName == "") {
  589. for (let i = 0; i < name.length; i++) {
  590. series[i].name = name[i];
  591. }
  592. this.options.legend["data"] = name;
  593. } else {
  594. const arr = legendName.split("|");
  595. for (let i = 0; i < arr.length; i++) {
  596. series[i].name = arr[i];
  597. }
  598. this.options.legend["data"] = arr;
  599. }
  600. },
  601. // 颜色修改、宽度修改
  602. setOptionsColor() {
  603. const optionsSetup = this.optionsSetup;
  604. const customColor = optionsSetup.customColor;
  605. const series = this.options.series;
  606. const arrColor = [];
  607. for (let i = 0; i < customColor.length; i++) {
  608. arrColor.push(customColor[i].color);
  609. }
  610. if (!customColor) return;
  611. for (const key in series) {
  612. const itemStyle = {
  613. color: arrColor[key],
  614. };
  615. const lineStyle = {
  616. color: arrColor[key],
  617. width: optionsSetup.lineWidth,
  618. };
  619. this.options.series[key].itemStyle = itemStyle;
  620. this.options.series[key].lineStyle = lineStyle;
  621. }
  622. },
  623. // 数据解析
  624. setOptionsData(e, paramsConfig) {
  625. const optionsSetup = this.optionsSetup;
  626. const optionsData = this.optionsData; // 数据类型 静态 or 动态
  627. // 联动接收者逻辑开始
  628. optionsData.dynamicData = optionsData.dynamicData || {}; // 兼容 dynamicData undefined
  629. const myDynamicData = optionsData.dynamicData;
  630. clearInterval(this.flagInter); // 不管咋,先干掉上一次的定时任务,避免多跑
  631. if (
  632. e &&
  633. optionsData.dataType !== "staticData" &&
  634. Object.keys(myDynamicData.contextData).length
  635. ) {
  636. const keyArr = Object.keys(myDynamicData.contextData);
  637. paramsConfig.forEach((conf) => {
  638. if (keyArr.includes(conf.targetKey)) {
  639. myDynamicData.contextData[conf.targetKey] = e[conf.originKey];
  640. }
  641. });
  642. }
  643. // 联动接收者逻辑结束
  644. optionsData.dataType == "staticData"
  645. ? this.staticDataFn(optionsData.staticData, optionsSetup)
  646. : this.dynamicDataFn(
  647. optionsData.dynamicData,
  648. optionsData.refreshTime,
  649. optionsSetup
  650. );
  651. },
  652. //去重
  653. setUnique(arr) {
  654. let newArr = [];
  655. arr.forEach((item) => {
  656. return newArr.includes(item) ? "" : newArr.push(item);
  657. });
  658. return newArr;
  659. },
  660. //静态数据
  661. staticDataFn(val) {
  662. //数据
  663. let xAxisList = [];
  664. let yAxisList = [];
  665. let arrayList = [];
  666. const legendName = [];
  667. for (const i in val) {
  668. xAxisList[i] = val[i].axis;
  669. yAxisList[i] = val[i].name;
  670. }
  671. xAxisList = this.setUnique(xAxisList);
  672. yAxisList = this.setUnique(yAxisList);
  673. for (const i in yAxisList) {
  674. const data = new Array(xAxisList.length).fill(0);
  675. for (const j in xAxisList) {
  676. for (const k in val) {
  677. if (val[k].name == yAxisList[i]) {
  678. if (val[k].axis == xAxisList[j]) {
  679. data[j] = val[k].data;
  680. }
  681. }
  682. }
  683. }
  684. arrayList.push({
  685. name: yAxisList[i],
  686. data: data,
  687. });
  688. legendName.push(yAxisList[i]);
  689. }
  690. this.options.series[0]["name"] = arrayList[0].name;
  691. this.options.series[0]["data"] = arrayList[0].data;
  692. this.options.series[1]["name"] = arrayList[1].name;
  693. this.options.series[1]["data"] = arrayList[1].data;
  694. this.options.xAxis[0]["data"] = xAxisList;
  695. this.options.xAxis[1]["data"] = xAxisList;
  696. this.options.legend["data"] = legendName;
  697. this.setOptionsLegendName(legendName);
  698. },
  699. // 动态数据
  700. dynamicDataFn(val, refreshTime, optionsSetup) {
  701. if (!val) return;
  702. if (this.ispreview) {
  703. this.getEchartData(val, optionsSetup);
  704. this.flagInter = setInterval(() => {
  705. this.getEchartData(val, optionsSetup);
  706. }, refreshTime);
  707. } else {
  708. this.getEchartData(val, optionsSetup);
  709. }
  710. },
  711. getEchartData(val, optionsSetup) {
  712. const data = this.queryEchartsData(val);
  713. data.then((res) => {
  714. this.renderingFn(optionsSetup, res);
  715. });
  716. },
  717. renderingFn(optionsSetup, val) {
  718. const legendName = [];
  719. this.options.xAxis[0]["data"] = val.xAxis;
  720. this.options.xAxis[1]["data"] = val.xAxis;
  721. if (val.series[0].type == "line") {
  722. this.options.series[0]["name"] = val.series[0].name;
  723. this.options.series[0]["data"] = val.series[0].data;
  724. this.options.series[1]["name"] = val.series[1].name;
  725. this.options.series[1]["data"] = val.series[1].data;
  726. legendName.push(val.series[0].name);
  727. legendName.push(val.series[1].name);
  728. }
  729. this.options.legend["data"] = legendName;
  730. this.setOptionsLegendName(legendName);
  731. },
  732. },
  733. };
  734. </script>
  735. <style scoped lang="scss">
  736. .echarts {
  737. width: 100%;
  738. height: 100%;
  739. overflow: hidden;
  740. }
  741. </style>