widgetLinechart.vue 15 KB

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