widgetBarCompareChart.vue 18 KB

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