widgetBarchart.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <template>
  2. <div :style="styleObj">
  3. <v-chart ref="myVChart" :options="options" autoresize/>
  4. </div>
  5. </template>
  6. <script>
  7. import {
  8. originWidgetLinkageLogic,
  9. targetWidgetLinkageLogic,
  10. } from "@/views/bigscreenDesigner/designer/linkageLogic";
  11. export default {
  12. name: "WidgetBarchart",
  13. components: {},
  14. props: {
  15. value: Object,
  16. ispreview: Boolean,
  17. widgetIndex: {
  18. type: Number,
  19. default: 0,
  20. }, // 当前组件,在工作区变量widgetInWorkbench中的索引
  21. },
  22. data() {
  23. return {
  24. options: {
  25. grid: {},
  26. legend: {
  27. textStyle: {
  28. color: "#fff",
  29. },
  30. },
  31. xAxis: {
  32. type: "category",
  33. data: [],
  34. axisLabel: {
  35. show: true,
  36. textStyle: {
  37. color: "#fff",
  38. },
  39. },
  40. },
  41. yAxis: {
  42. type: "value",
  43. data: [],
  44. axisLabel: {
  45. show: true,
  46. textStyle: {
  47. color: "#fff",
  48. },
  49. },
  50. },
  51. series: [
  52. {
  53. data: [],
  54. type: "bar",
  55. barGap: "0%",
  56. itemStyle: {
  57. borderRadius: null,
  58. },
  59. },
  60. ],
  61. },
  62. optionsStyle: {}, // 样式
  63. optionsData: {}, // 数据
  64. optionsSetup: {},
  65. flagInter: null,
  66. };
  67. },
  68. computed: {
  69. styleObj() {
  70. return {
  71. position: this.ispreview ? "absolute" : "static",
  72. width: this.optionsStyle.width + "px",
  73. height: this.optionsStyle.height + "px",
  74. left: this.optionsStyle.left + "px",
  75. top: this.optionsStyle.top + "px",
  76. background: this.optionsSetup.background,
  77. };
  78. },
  79. allComponentLinkage() {
  80. return this.$store.state.designer.allComponentLinkage;
  81. },
  82. },
  83. watch: {
  84. value: {
  85. handler(val) {
  86. this.optionsStyle = val.position;
  87. this.optionsData = val.data;
  88. this.optionsCollapse = val.setup;
  89. this.optionsSetup = val.setup;
  90. this.editorOptions();
  91. },
  92. deep: true,
  93. },
  94. },
  95. mounted() {
  96. this.optionsStyle = this.value.position;
  97. this.optionsData = this.value.data;
  98. this.optionsCollapse = this.value.setup;
  99. this.optionsSetup = this.value.setup;
  100. this.editorOptions();
  101. targetWidgetLinkageLogic(this); // 联动-目标组件逻辑
  102. originWidgetLinkageLogic(this); // 联动-源组件逻辑
  103. },
  104. methods: {
  105. // 修改图标options属性
  106. editorOptions() {
  107. this.setOptionsTitle();
  108. this.setOptionsX();
  109. this.setOptionsY();
  110. this.setOptionsLegend();
  111. this.setOptionsTooltip();
  112. this.setOptionsMargin();
  113. this.setOptionsData();
  114. },
  115. // 标题修改
  116. setOptionsTitle() {
  117. const optionsSetup = this.optionsSetup;
  118. const title = {};
  119. title.text = optionsSetup.titleText;
  120. title.show = optionsSetup.isNoTitle;
  121. title.left = optionsSetup.textAlign;
  122. title.textStyle = {
  123. color: optionsSetup.textColor,
  124. fontSize: optionsSetup.textFontSize,
  125. fontWeight: optionsSetup.textFontWeight,
  126. fontStyle: optionsSetup.textFontStyle,
  127. };
  128. title.subtext = optionsSetup.subText;
  129. title.subtextStyle = {
  130. color: optionsSetup.subTextColor,
  131. fontWeight: optionsSetup.subTextFontWeight,
  132. fontSize: optionsSetup.subTextFontSize,
  133. fontStyle: optionsSetup.subTextFontStyle,
  134. };
  135. this.options.title = title;
  136. },
  137. // X轴设置
  138. setOptionsX() {
  139. const optionsSetup = this.optionsSetup;
  140. const xAxis = {
  141. type: "category",
  142. // 坐标轴是否显示
  143. show: optionsSetup.hideX,
  144. // 坐标轴名称
  145. name: optionsSetup.nameX,
  146. nameTextStyle: {
  147. color: optionsSetup.nameColorX,
  148. fontSize: optionsSetup.nameFontSizeX,
  149. },
  150. // 轴反转
  151. inverse: optionsSetup.reversalX,
  152. axisLabel: {
  153. show: true,
  154. // 文字间隔
  155. interval: optionsSetup.textInterval,
  156. // 文字角度
  157. rotate: optionsSetup.textAngleX,
  158. textStyle: {
  159. // 坐标文字颜色
  160. color: optionsSetup.colorX,
  161. fontSize: optionsSetup.fontSizeX,
  162. },
  163. },
  164. axisLine: {
  165. show: true,
  166. lineStyle: {
  167. color: optionsSetup.lineColorX,
  168. width: optionsSetup.lineWidthX,
  169. },
  170. },
  171. splitLine: {
  172. show: optionsSetup.isShowSplitLineX,
  173. lineStyle: {
  174. color: optionsSetup.splitLineColorX,
  175. width: optionsSetup.splitLineWidthX,
  176. },
  177. },
  178. };
  179. this.options.xAxis = xAxis;
  180. },
  181. // Y轴设置
  182. setOptionsY() {
  183. const optionsSetup = this.optionsSetup;
  184. const yAxis = {
  185. type: "value",
  186. scale: optionsSetup.scale,
  187. // 均分
  188. splitNumber: optionsSetup.splitNumberY,
  189. // 坐标轴是否显示
  190. show: optionsSetup.isShowY,
  191. // 坐标轴名称
  192. name: optionsSetup.textNameY,
  193. nameTextStyle: {
  194. color: optionsSetup.nameColorY,
  195. fontSize: optionsSetup.nameFontSizeY,
  196. },
  197. // 轴反转
  198. inverse: optionsSetup.reversalY,
  199. axisLabel: {
  200. show: true,
  201. // 文字角度
  202. rotate: optionsSetup.textAngleY,
  203. textStyle: {
  204. // 坐标文字颜色
  205. color: optionsSetup.colorY,
  206. fontSize: optionsSetup.fontSizeY,
  207. },
  208. },
  209. axisLine: {
  210. show: true,
  211. lineStyle: {
  212. color: optionsSetup.lineColorY,
  213. width: optionsSetup.lineWidthY,
  214. },
  215. },
  216. splitLine: {
  217. show: optionsSetup.isShowSplitLineY,
  218. lineStyle: {
  219. color: optionsSetup.splitLineColorY,
  220. width: optionsSetup.splitLineWidthY,
  221. },
  222. },
  223. };
  224. this.options.yAxis = yAxis;
  225. },
  226. // tooltip 设置
  227. setOptionsTooltip() {
  228. const optionsSetup = this.optionsSetup;
  229. const tooltip = {
  230. trigger: "item",
  231. show: true,
  232. textStyle: {
  233. color: optionsSetup.tipsColor,
  234. fontSize: optionsSetup.tipsFontSize,
  235. },
  236. };
  237. this.options.tooltip = tooltip;
  238. },
  239. // 边距设置
  240. setOptionsMargin() {
  241. const optionsSetup = this.optionsSetup;
  242. const grid = {
  243. left: optionsSetup.marginLeft,
  244. right: optionsSetup.marginRight,
  245. bottom: optionsSetup.marginBottom,
  246. top: optionsSetup.marginTop,
  247. containLabel: true,
  248. };
  249. this.options.grid = grid;
  250. },
  251. // 图例
  252. setOptionsLegend() {
  253. const optionsSetup = this.optionsSetup;
  254. const legend = this.options.legend;
  255. legend.show = optionsSetup.isShowLegend;
  256. legend.left = optionsSetup.lateralPosition;
  257. legend.top = optionsSetup.longitudinalPosition;
  258. legend.bottom = optionsSetup.longitudinalPosition;
  259. legend.orient = optionsSetup.layoutFront;
  260. legend.textStyle = {
  261. color: optionsSetup.legendColor,
  262. fontSize: optionsSetup.legendFontSize,
  263. };
  264. legend.itemWidth = optionsSetup.legendWidth;
  265. },
  266. // 图例名称设置
  267. setOptionsLegendName(name) {
  268. const optionsSetup = this.optionsSetup;
  269. const series = this.options.series;
  270. const legendName = optionsSetup.legendName;
  271. // 图例没有手动写则显示原值,写了则显示新值
  272. if (null == legendName || legendName == "") {
  273. for (let i = 0; i < name.length; i++) {
  274. series[i].name = name[i];
  275. }
  276. this.options.legend["data"] = name;
  277. } else {
  278. const arr = legendName.split("|");
  279. for (let i = 0; i < arr.length; i++) {
  280. series[i].name = arr[i];
  281. }
  282. this.options.legend["data"] = arr;
  283. }
  284. },
  285. //获取堆叠样式
  286. getStackStyle() {
  287. const optionsSetup = this.optionsSetup;
  288. let style = "";
  289. if (optionsSetup.stackStyle == "upDown") {
  290. style = "total";
  291. }
  292. return style;
  293. },
  294. // 获得位置
  295. getOptionsPosition() {
  296. const optionsSetup = this.optionsSetup;
  297. let position = "";
  298. if (optionsSetup.verticalShow) {
  299. position = "right";
  300. } else {
  301. position = "top";
  302. }
  303. return position;
  304. },
  305. // 数据解析
  306. setOptionsData(e, paramsConfig) {
  307. const optionsData = this.optionsData; // 数据类型 静态 or 动态
  308. // 联动接收者逻辑开始
  309. optionsData.dynamicData = optionsData.dynamicData || {}; // 兼容 dynamicData undefined
  310. const myDynamicData = optionsData.dynamicData;
  311. clearInterval(this.flagInter); // 不管咋,先干掉上一次的定时任务,避免多跑
  312. if (
  313. e &&
  314. optionsData.dataType !== "staticData" &&
  315. Object.keys(myDynamicData.contextData).length
  316. ) {
  317. const keyArr = Object.keys(myDynamicData.contextData);
  318. paramsConfig.forEach((conf) => {
  319. if (keyArr.includes(conf.targetKey)) {
  320. myDynamicData.contextData[conf.targetKey] = e[conf.originKey];
  321. }
  322. });
  323. }
  324. // 联动接收者逻辑结束
  325. optionsData.dataType == "staticData"
  326. ? this.staticDataFn(optionsData.staticData)
  327. : this.dynamicDataFn(optionsData.refreshTime);
  328. },
  329. // 静态数据
  330. staticDataFn(val) {
  331. const optionsSetup = this.optionsSetup;
  332. //颜色
  333. const customColor = optionsSetup.customColor;
  334. const arrColor = [];
  335. for (let i = 0; i < customColor.length; i++) {
  336. arrColor.push(customColor[i].color);
  337. }
  338. const series = this.options.series;
  339. let axis = [];
  340. let data = [];
  341. for (const i in val) {
  342. axis[i] = val[i].axis;
  343. data[i] = val[i].data;
  344. }
  345. const legendName = [];
  346. legendName.push("bar");
  347. // x轴
  348. if (optionsSetup.verticalShow) {
  349. this.options.xAxis.data = [];
  350. this.options.yAxis.data = axis;
  351. this.options.xAxis.type = "value";
  352. this.options.yAxis.type = "category";
  353. } else {
  354. this.options.xAxis.data = axis;
  355. this.options.yAxis.data = [];
  356. this.options.xAxis.type = "category";
  357. this.options.yAxis.type = "value";
  358. }
  359. for (const i in series) {
  360. if (series[i].type == "bar") {
  361. series[i].type = "bar";
  362. series[i].barGap = "0%";
  363. series[i].barWidth = optionsSetup.maxWidth;
  364. series[i].barMinHeight = optionsSetup.minHeight;
  365. series[i].label = {
  366. show: optionsSetup.isShow,
  367. position: this.getOptionsPosition(),
  368. distance: optionsSetup.distance,
  369. fontSize: optionsSetup.fontSize,
  370. color: optionsSetup.dataColor,
  371. fontWeight: optionsSetup.fontWeight,
  372. formatter: !!optionsSetup.percentSign ? '{c}%' : '{c}'
  373. };
  374. // 获取颜色样式
  375. if (optionsSetup.colorStyle == 'same') {
  376. series[i].itemStyle = {
  377. normal: {
  378. color: arrColor[i],
  379. barBorderRadius: optionsSetup.radius,
  380. },
  381. };
  382. } else {
  383. series[i].itemStyle = {
  384. normal: {
  385. color: (params) => {
  386. return arrColor[params.dataIndex];
  387. },
  388. barBorderRadius: optionsSetup.radius,
  389. },
  390. };
  391. }
  392. series[i].data = data;
  393. this.options.legend["data"] = legendName;
  394. this.setOptionsLegendName(legendName);
  395. }
  396. }
  397. },
  398. // 动态数据
  399. dynamicDataFn(refreshTime) {
  400. const optionsSetup = this.optionsSetup;
  401. const optionsData = this.optionsData;
  402. const val = optionsData.dynamicData;
  403. if (!val) return;
  404. if (this.ispreview) {
  405. this.getEchartData(val, optionsSetup);
  406. this.flagInter = setInterval(() => {
  407. this.getEchartData(val, optionsSetup);
  408. }, refreshTime);
  409. } else {
  410. this.getEchartData(val, optionsSetup);
  411. }
  412. },
  413. getEchartData(val, optionsSetup) {
  414. const data = this.queryEchartsData(val);
  415. data.then((res) => {
  416. this.renderingFn(optionsSetup, res);
  417. });
  418. },
  419. renderingFn(optionsSetup, val) {
  420. //颜色
  421. const customColor = optionsSetup.customColor;
  422. const arrColor = [];
  423. for (let i = 0; i < customColor.length; i++) {
  424. arrColor.push(customColor[i].color);
  425. }
  426. const series = [];
  427. const legendName = [];
  428. // x轴
  429. if (optionsSetup.verticalShow) {
  430. this.options.xAxis.data = [];
  431. this.options.yAxis.data = val.xAxis;
  432. this.options.xAxis.type = "value";
  433. this.options.yAxis.type = "category";
  434. } else {
  435. this.options.xAxis.data = val.xAxis;
  436. this.options.yAxis.data = [];
  437. this.options.xAxis.type = "category";
  438. this.options.yAxis.type = "value";
  439. }
  440. for (const i in val.series) {
  441. legendName.push(val.series[i].name);
  442. const obj = {};
  443. if (val.series[i].type == "bar") {
  444. obj.type = "bar";
  445. obj.barGap = "0%";
  446. obj.stack = this.getStackStyle();
  447. obj.barWidth = optionsSetup.maxWidth;
  448. obj.barMinHeight = optionsSetup.minHeight;
  449. obj.label = {
  450. show: optionsSetup.isShow,
  451. position: this.getOptionsPosition(),
  452. distance: optionsSetup.distance,
  453. fontSize: optionsSetup.fontSize,
  454. color: optionsSetup.dataColor,
  455. fontWeight: optionsSetup.fontWeight,
  456. formatter: !!optionsSetup.percentSign ? '{c}%' : '{c}'
  457. };
  458. // 获取颜色样式
  459. if (optionsSetup.colorStyle == 'same') {
  460. obj.itemStyle = {
  461. normal: {
  462. color: arrColor[i],
  463. barBorderRadius: optionsSetup.radius,
  464. },
  465. };
  466. } else {
  467. obj.itemStyle = {
  468. normal: {
  469. color: (params) => {
  470. return arrColor[params.dataIndex];
  471. },
  472. barBorderRadius: optionsSetup.radius,
  473. },
  474. };
  475. }
  476. obj.data = val.series[i].data;
  477. series.push(obj);
  478. }
  479. }
  480. this.options.series = series;
  481. this.options.legend["data"] = legendName;
  482. this.setOptionsLegendName(legendName);
  483. },
  484. },
  485. };
  486. </script>
  487. <style scoped lang="scss">
  488. .echarts {
  489. width: 100%;
  490. height: 100%;
  491. overflow: hidden;
  492. }
  493. </style>