widgetBarLineStackChart.vue 20 KB

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