widgetBarCompareChart.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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=xrJwcCF3NZ
  11. components: {},
  12. props: {
  13. value: Object,
  14. ispreview: Boolean,
  15. },
  16. data() {
  17. return {
  18. options: {
  19. title: {
  20. //text: '柱状对比图',
  21. x: "center",
  22. textStyle: {
  23. color: "#ffffff",
  24. },
  25. },
  26. //边距
  27. grid: [
  28. {
  29. //左
  30. show: false, //边框线
  31. left: "4%",
  32. top: 60,
  33. bottom: 10,
  34. containLabel: true,
  35. width: "40%",
  36. },
  37. {
  38. //中间字体位置
  39. show: false,
  40. left: "50.5%",
  41. top: 60,
  42. bottom: 25,
  43. width: "0%",
  44. },
  45. {
  46. //右
  47. show: false,
  48. right: "4%",
  49. top: 60,
  50. bottom: 10,
  51. containLabel: true,
  52. width: "40%",
  53. },
  54. ],
  55. //图例
  56. legend: {
  57. textStyle: {
  58. color: "#fff",
  59. textAlign: "center",
  60. },
  61. //itemGap:80,
  62. //itemWidth: 0
  63. },
  64. xAxis: [
  65. {
  66. // 左
  67. splitNumber: 2,
  68. show: true,
  69. type: "value",
  70. inverse: true,
  71. axisLine: {
  72. //底分割线
  73. show: false,
  74. },
  75. axisTick: {
  76. show: false,
  77. },
  78. position: "bottom",
  79. axisLabel: {
  80. // x轴
  81. show: true,
  82. textStyle: {
  83. color: "#ffffff",
  84. fontSize: 12,
  85. },
  86. },
  87. splitLine: {
  88. // 竖分割线
  89. show: true,
  90. lineStyle: {
  91. color: "#57617f",
  92. width: 1,
  93. type: "solid",
  94. },
  95. },
  96. },
  97. {
  98. gridIndex: 1,
  99. show: false,
  100. },
  101. {
  102. // 右
  103. gridIndex: 2,
  104. show: true,
  105. type: "value",
  106. axisLine: {
  107. show: false,
  108. },
  109. axisTick: {
  110. show: false,
  111. },
  112. position: "bottom",
  113. axisLabel: {
  114. show: true,
  115. textStyle: {
  116. color: "#ffffff",
  117. fontSize: 12,
  118. },
  119. },
  120. splitLine: {
  121. show: true,
  122. lineStyle: {
  123. color: "#57617f",
  124. width: 1,
  125. type: "solid",
  126. },
  127. },
  128. },
  129. ],
  130. yAxis: [
  131. {
  132. type: "category",
  133. inverse: true,
  134. position: "right",
  135. axisLine: {
  136. show: false,
  137. },
  138. axisTick: {
  139. show: false,
  140. },
  141. axisLabel: {
  142. show: false,
  143. },
  144. data: [],
  145. },
  146. {
  147. //处理轴数据
  148. gridIndex: 1,
  149. type: "category",
  150. inverse: true,
  151. position: "left",
  152. axisLine: {
  153. show: false,
  154. },
  155. axisTick: {
  156. show: false,
  157. },
  158. axisLabel: {
  159. show: true,
  160. textStyle: {
  161. align: "center",
  162. color: "#ffffff",
  163. fontSize: 14,
  164. },
  165. },
  166. data: [],
  167. },
  168. {
  169. gridIndex: 2,
  170. type: "category",
  171. inverse: true,
  172. position: "left",
  173. axisLine: {
  174. show: false,
  175. },
  176. axisTick: {
  177. show: false,
  178. },
  179. axisLabel: {
  180. show: false,
  181. },
  182. },
  183. ],
  184. series: [
  185. {
  186. name: "",
  187. type: "bar",
  188. barGap: 20,
  189. barWidth: 15,
  190. label: {
  191. normal: {
  192. show: true,
  193. color: "red",
  194. position: "insideLeft",
  195. textStyle: {
  196. color: "#ffffff",
  197. },
  198. },
  199. emphasis: {
  200. show: false,
  201. },
  202. },
  203. itemStyle: {
  204. normal: {
  205. color: "#36c5e7",
  206. barBorderRadius: [8, 0, 0, 8],
  207. },
  208. emphasis: {
  209. show: false,
  210. },
  211. },
  212. data: [],
  213. },
  214. {
  215. name: "",
  216. type: "bar",
  217. barGap: 20,
  218. barWidth: 15,
  219. xAxisIndex: 2,
  220. yAxisIndex: 2,
  221. label: {
  222. normal: {
  223. show: true,
  224. color: "red",
  225. position: "insideRight",
  226. textStyle: {
  227. color: "#ffffff",
  228. },
  229. },
  230. },
  231. itemStyle: {
  232. normal: {
  233. color: "#e68b55",
  234. barBorderRadius: [0, 8, 8, 0],
  235. },
  236. emphasis: {
  237. show: false,
  238. },
  239. },
  240. data: [],
  241. },
  242. ],
  243. },
  244. optionsStyle: {},
  245. optionsData: {},
  246. optionsSetup: {},
  247. flagInter: null,
  248. };
  249. },
  250. computed: {
  251. styleObj() {
  252. return {
  253. position: this.ispreview ? "absolute" : "static",
  254. width: this.optionsStyle.width + "px",
  255. height: this.optionsStyle.height + "px",
  256. left: this.optionsStyle.left + "px",
  257. top: this.optionsStyle.top + "px",
  258. background: this.optionsSetup.background,
  259. };
  260. },
  261. allComponentLinkage() {
  262. return this.$store.state.designer.allComponentLinkage;
  263. },
  264. },
  265. watch: {
  266. value: {
  267. handler(val) {
  268. this.optionsStyle = val.position;
  269. this.optionsData = val.data;
  270. this.optionsCollapse = val.setup;
  271. this.optionsSetup = val.setup;
  272. this.editorOptions();
  273. },
  274. deep: true,
  275. },
  276. },
  277. mounted() {
  278. this.optionsStyle = this.value.position;
  279. this.optionsData = this.value.data;
  280. this.optionsCollapse = this.value.setup;
  281. this.optionsSetup = this.value.setup;
  282. this.editorOptions();
  283. targetWidgetLinkageLogic(this); // 联动-目标组件逻辑
  284. },
  285. methods: {
  286. // 修改图标options属性
  287. editorOptions() {
  288. this.setOptionsTitle();
  289. this.setOptionsXLeft();
  290. this.setOptionsXRight();
  291. this.setOptionsY();
  292. this.setOptionsTop();
  293. this.setOptionsTooltip();
  294. this.setOptionsGrid();
  295. this.setOptionsLegend();
  296. this.setOptionsColor();
  297. this.setOptionsData();
  298. },
  299. // 标题修改
  300. setOptionsTitle() {
  301. const optionsSetup = this.optionsSetup;
  302. const title = {};
  303. title.text = optionsSetup.titleText;
  304. title.show = optionsSetup.isNoTitle;
  305. title.left = optionsSetup.textAlign;
  306. title.textStyle = {
  307. color: optionsSetup.textColor,
  308. fontSize: optionsSetup.textFontSize,
  309. fontWeight: optionsSetup.textFontWeight,
  310. fontStyle: optionsSetup.textFontStyle,
  311. };
  312. title.subtext = optionsSetup.subText;
  313. title.subtextStyle = {
  314. color: optionsSetup.subTextColor,
  315. fontWeight: optionsSetup.subTextFontWeight,
  316. fontSize: optionsSetup.subTextFontSize,
  317. fontStyle: optionsSetup.subTextFontStyle,
  318. };
  319. this.options.title = title;
  320. },
  321. // 左X轴设置
  322. setOptionsXLeft() {
  323. const optionsSetup = this.optionsSetup;
  324. const xAxisLeft = {
  325. splitNumber: optionsSetup.splitNumberLeft,
  326. type: "value",
  327. show: optionsSetup.hideXLeft,
  328. inverse: true,
  329. //X轴线
  330. axisLine: {
  331. show: optionsSetup.lineXLeft,
  332. lineStyle: {
  333. color: optionsSetup.lineColorXLeft,
  334. },
  335. },
  336. axisTick: {
  337. show: optionsSetup.tickLineLeft,
  338. },
  339. position: optionsSetup.positionXLeft,
  340. axisLabel: {
  341. // x轴
  342. show: true,
  343. textStyle: {
  344. color: optionsSetup.colorXLeft,
  345. fontSize: optionsSetup.fontSizeXLeft,
  346. },
  347. },
  348. splitLine: {
  349. // 分割线
  350. show: optionsSetup.isShowSplitLineLeft,
  351. lineStyle: {
  352. color: optionsSetup.splitLineColorLeft,
  353. width: optionsSetup.splitLineFontWidthLeft,
  354. type: "solid",
  355. },
  356. },
  357. };
  358. this.options.xAxis[0] = xAxisLeft;
  359. },
  360. // 右X轴设置
  361. setOptionsXRight() {
  362. const optionsSetup = this.optionsSetup;
  363. const xAxisRight = {
  364. gridIndex: 2,
  365. splitNumber: optionsSetup.splitNumberRight,
  366. show: optionsSetup.hideXRight,
  367. type: "value",
  368. axisLine: {
  369. //X轴线
  370. show: optionsSetup.lineXRight,
  371. lineStyle: {
  372. color: optionsSetup.lineColorXRight,
  373. },
  374. },
  375. axisTick: {
  376. show: optionsSetup.tickLineRight,
  377. },
  378. position: optionsSetup.positionXRight,
  379. axisLabel: {
  380. // x轴
  381. show: true,
  382. textStyle: {
  383. color: optionsSetup.colorXRight,
  384. fontSize: optionsSetup.fontSizeXRight,
  385. },
  386. },
  387. splitLine: {
  388. // 分割线
  389. show: optionsSetup.isShowSplitLineRight,
  390. lineStyle: {
  391. color: optionsSetup.splitLineColorRight,
  392. width: optionsSetup.splitLineFontWidthRight,
  393. type: "solid",
  394. },
  395. },
  396. };
  397. this.options.xAxis[2] = xAxisRight;
  398. },
  399. // Y轴设置
  400. setOptionsY() {
  401. const optionsSetup = this.optionsSetup;
  402. const axisLine = {
  403. show: optionsSetup.lineY,
  404. lineStyle: {
  405. color: optionsSetup.lineColorY,
  406. },
  407. };
  408. const axisTick = {
  409. show: optionsSetup.tickLineY,
  410. };
  411. const axisLabel = {
  412. show: optionsSetup.hideY,
  413. textStyle: {
  414. align: optionsSetup.textAlignY,
  415. color: optionsSetup.colorY,
  416. fontSize: optionsSetup.fontSizeY,
  417. },
  418. };
  419. this.options.yAxis[1]["axisLine"] = axisLine;
  420. this.options.yAxis[1]["axisTick"] = axisTick;
  421. this.options.yAxis[1]["axisLabel"] = axisLabel;
  422. },
  423. // 数值设定、柱体设置
  424. setOptionsTop() {
  425. const optionsSetup = this.optionsSetup;
  426. const series = this.options.series;
  427. for (const key in series) {
  428. if (series[key].type == "bar") {
  429. (series[0].label = {
  430. normal: {
  431. show: optionsSetup.isShow,
  432. position: "insideLeft",
  433. textStyle: {
  434. fontSize: optionsSetup.fontSize,
  435. color: optionsSetup.dataColor,
  436. fontWeight: optionsSetup.fontWeight,
  437. },
  438. },
  439. emphasis: {
  440. show: false,
  441. },
  442. }),
  443. (series[1].label = {
  444. normal: {
  445. show: optionsSetup.isShow,
  446. color: "red",
  447. position: "insideRight",
  448. textStyle: {
  449. fontSize: optionsSetup.fontSize,
  450. color: optionsSetup.dataColor,
  451. fontWeight: optionsSetup.fontWeight,
  452. },
  453. },
  454. emphasis: {
  455. show: false,
  456. },
  457. }),
  458. (series[key].barWidth = optionsSetup.maxWidth);
  459. }
  460. }
  461. this.options.series = series;
  462. },
  463. // tooltip 提示语设置
  464. setOptionsTooltip() {
  465. const optionsSetup = this.optionsSetup;
  466. const tooltip = {
  467. trigger: "item",
  468. show: true,
  469. textStyle: {
  470. color: optionsSetup.tipsColor,
  471. fontSize: optionsSetup.tipsFontSize,
  472. },
  473. };
  474. this.options.tooltip = tooltip;
  475. },
  476. // 边距设置
  477. setOptionsGrid() {
  478. const optionsSetup = this.optionsSetup;
  479. const grid = [
  480. {
  481. //左
  482. show: optionsSetup.frameLineLeft,
  483. borderColor: optionsSetup.borderColorLeft,
  484. borderWidth: optionsSetup.borderWidthLeft,
  485. left: optionsSetup.marginLeftRight,
  486. top: optionsSetup.marginTop,
  487. bottom: optionsSetup.marginBottom,
  488. containLabel: true,
  489. width: "40%",
  490. },
  491. {
  492. //中间字体位置
  493. show: false,
  494. left: "51%",
  495. top: optionsSetup.marginTop,
  496. bottom: optionsSetup.marginBottom + 15,
  497. width: "0%",
  498. },
  499. {
  500. //右
  501. show: optionsSetup.frameLineRight,
  502. borderColor: optionsSetup.borderColorRight,
  503. borderWidth: optionsSetup.borderWidthRight,
  504. right: optionsSetup.marginLeftRight,
  505. top: optionsSetup.marginTop,
  506. bottom: optionsSetup.marginBottom,
  507. containLabel: true,
  508. width: "40%",
  509. },
  510. ];
  511. this.options.grid = grid;
  512. },
  513. // 图例操作
  514. setOptionsLegend() {
  515. const optionsSetup = this.optionsSetup;
  516. const legend = this.options.legend;
  517. legend.show = optionsSetup.isShowLegend;
  518. legend.left = optionsSetup.lateralPosition;
  519. legend.top = optionsSetup.longitudinalPosition;
  520. legend.bottom = optionsSetup.longitudinalPosition;
  521. legend.orient = optionsSetup.layoutFront;
  522. legend.textStyle = {
  523. color: optionsSetup.legendColor,
  524. fontSize: optionsSetup.legendFontSize,
  525. };
  526. legend.itemWidth = optionsSetup.legendWidth;
  527. },
  528. // 图例名称设置
  529. setOptionsLegendName(name) {
  530. const optionsSetup = this.optionsSetup;
  531. const series = this.options.series;
  532. const legendName = optionsSetup.legendName;
  533. // 图例没有手动写则显示原值,写了则显示新值
  534. if (null == legendName || legendName == "") {
  535. for (let i = 0; i < name.length; i++) {
  536. series[i].name = name[i];
  537. }
  538. this.options.legend["data"] = name;
  539. } else {
  540. const arr = legendName.split("|");
  541. for (let i = 0; i < arr.length; i++) {
  542. series[i].name = arr[i];
  543. }
  544. this.options.legend["data"] = arr;
  545. }
  546. },
  547. // 颜色修改、圆角修改
  548. setOptionsColor() {
  549. const optionsSetup = this.optionsSetup;
  550. const customColor = optionsSetup.customColor;
  551. if (!customColor) return;
  552. const itemStyleLeft = {
  553. normal: {
  554. color: customColor[0].color,
  555. barBorderRadius: [optionsSetup.radius, 0, 0, optionsSetup.radius],
  556. },
  557. emphasis: {
  558. show: false,
  559. },
  560. };
  561. const itemStyleRight = {
  562. normal: {
  563. color: customColor[1].color,
  564. barBorderRadius: [0, optionsSetup.radius, optionsSetup.radius, 0],
  565. },
  566. emphasis: {
  567. show: false,
  568. },
  569. };
  570. this.options.series[0].itemStyle = itemStyleLeft;
  571. this.options.series[1].itemStyle = itemStyleRight;
  572. },
  573. // 数据解析
  574. setOptionsData(e, paramsConfig) {
  575. const optionsSetup = this.optionsSetup;
  576. const optionsData = this.optionsData; // 数据类型 静态 or 动态
  577. // 联动接收者逻辑开始
  578. optionsData.dynamicData = optionsData.dynamicData || {}; // 兼容 dynamicData undefined
  579. const myDynamicData = optionsData.dynamicData;
  580. clearInterval(this.flagInter); // 不管咋,先干掉上一次的定时任务,避免多跑
  581. if (
  582. e &&
  583. optionsData.dataType !== "staticData" &&
  584. Object.keys(myDynamicData.contextData).length
  585. ) {
  586. const keyArr = Object.keys(myDynamicData.contextData);
  587. paramsConfig.forEach((conf) => {
  588. if (keyArr.includes(conf.targetKey)) {
  589. myDynamicData.contextData[conf.targetKey] = e[conf.originKey];
  590. }
  591. });
  592. }
  593. // 联动接收者逻辑结束
  594. optionsData.dataType == "staticData"
  595. ? this.staticDataFn(optionsData.staticData, optionsSetup)
  596. : this.dynamicDataFn(
  597. optionsData.dynamicData,
  598. optionsData.refreshTime,
  599. optionsSetup
  600. );
  601. },
  602. //去重
  603. setUnique(arr) {
  604. let newArr = [];
  605. arr.forEach((item) => {
  606. return newArr.includes(item) ? "" : newArr.push(item);
  607. });
  608. return newArr;
  609. },
  610. //静态数据
  611. staticDataFn(val) {
  612. //数据
  613. let xAxisList = [];
  614. let yAxisList = [];
  615. let arrayList = [];
  616. const legendName = [];
  617. for (const i in val) {
  618. xAxisList[i] = val[i].axis;
  619. yAxisList[i] = val[i].name;
  620. }
  621. xAxisList = this.setUnique(xAxisList);
  622. yAxisList = this.setUnique(yAxisList);
  623. for (const i in yAxisList) {
  624. const data = new Array(xAxisList.length).fill(0);
  625. for (const j in xAxisList) {
  626. for (const k in val) {
  627. if (val[k].name == yAxisList[i]) {
  628. if (val[k].axis == xAxisList[j]) {
  629. data[j] = val[k].data;
  630. }
  631. }
  632. }
  633. }
  634. arrayList.push({
  635. name: yAxisList[i],
  636. data: data,
  637. });
  638. legendName.push(yAxisList[i]);
  639. }
  640. this.options.series[0]["name"] = arrayList[0].name;
  641. this.options.series[0]["data"] = arrayList[0].data;
  642. this.options.series[1]["name"] = arrayList[1].name;
  643. this.options.series[1]["data"] = arrayList[1].data;
  644. this.options.yAxis[1]["data"] = xAxisList;
  645. this.options.legend["data"] = legendName;
  646. this.setOptionsLegendName(legendName);
  647. },
  648. // 动态数据
  649. dynamicDataFn(val, refreshTime, optionsSetup) {
  650. if (!val) return;
  651. if (this.ispreview) {
  652. this.getEchartData(val, optionsSetup);
  653. this.flagInter = setInterval(() => {
  654. this.getEchartData(val, optionsSetup);
  655. }, refreshTime);
  656. } else {
  657. this.getEchartData(val, optionsSetup);
  658. }
  659. },
  660. getEchartData(val, optionsSetup) {
  661. const data = this.queryEchartsData(val);
  662. data.then((res) => {
  663. this.renderingFn(optionsSetup, res);
  664. });
  665. },
  666. renderingFn(optionsSetup, val) {
  667. const legendName = [];
  668. this.options.yAxis[1]["data"] = val.xAxis;
  669. if (val.series[0].type == "bar") {
  670. this.options.series[0]["name"] = val.series[0].name;
  671. this.options.series[0]["data"] = val.series[0].data;
  672. this.options.series[1]["name"] = val.series[1].name;
  673. this.options.series[1]["data"] = val.series[1].data;
  674. legendName.push(val.series[0].name);
  675. legendName.push(val.series[1].name);
  676. }
  677. this.options.legend["data"] = legendName;
  678. this.setOptionsLegendName(legendName);
  679. },
  680. },
  681. };
  682. </script>
  683. <style scoped lang="scss">
  684. .echarts {
  685. width: 100%;
  686. height: 100%;
  687. overflow: hidden;
  688. }
  689. </style>