widgetAirBubbleMap.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. <template>
  2. <div :style="styleObj">
  3. <v-chart ref="myVChart" :option="options" autoresize/>
  4. </div>
  5. </template>
  6. <script>
  7. import {targetWidgetLinkageLogic} from "@/views/bigscreenDesigner/designer/linkageLogic";
  8. import "../../../../../../node_modules/echarts/map/js/china.js";
  9. import "../../../../../../node_modules/echarts/map/js/world.js";
  10. import "../../../../../../node_modules/echarts/map/js/province/anhui";
  11. import "../../../../../../node_modules/echarts/map/js/province/aomen";
  12. import "../../../../../../node_modules/echarts/map/js/province/beijing";
  13. import "../../../../../../node_modules/echarts/map/js/province/chongqing";
  14. import "../../../../../../node_modules/echarts/map/js/province/fujian";
  15. import "../../../../../../node_modules/echarts/map/js/province/gansu";
  16. import "../../../../../../node_modules/echarts/map/js/province/guangxi";
  17. import "../../../../../../node_modules/echarts/map/js/province/guizhou";
  18. import "../../../../../../node_modules/echarts/map/js/province/hainan";
  19. import "../../../../../../node_modules/echarts/map/js/province/hebei";
  20. import "../../../../../../node_modules/echarts/map/js/province/heilongjiang";
  21. import "../../../../../../node_modules/echarts/map/js/province/henan";
  22. import "../../../../../../node_modules/echarts/map/js/province/hubei";
  23. import "../../../../../../node_modules/echarts/map/js/province/hunan";
  24. import "../../../../../../node_modules/echarts/map/js/province/jiangsu";
  25. import "../../../../../../node_modules/echarts/map/js/province/jiangxi";
  26. import "../../../../../../node_modules/echarts/map/js/province/jilin";
  27. import "../../../../../../node_modules/echarts/map/js/province/liaoning";
  28. import "../../../../../../node_modules/echarts/map/js/province/neimenggu";
  29. import "../../../../../../node_modules/echarts/map/js/province/ningxia";
  30. import "../../../../../../node_modules/echarts/map/js/province/qinghai";
  31. import "../../../../../../node_modules/echarts/map/js/province/shandong";
  32. import "../../../../../../node_modules/echarts/map/js/province/shanghai";
  33. import "../../../../../../node_modules/echarts/map/js/province/shanxi";
  34. import "../../../../../../node_modules/echarts/map/js/province/shanxi1";
  35. import "../../../../../../node_modules/echarts/map/js/province/sichuan";
  36. import "../../../../../../node_modules/echarts/map/js/province/taiwan";
  37. import "../../../../../../node_modules/echarts/map/js/province/tianjin";
  38. import "../../../../../../node_modules/echarts/map/js/province/xianggang";
  39. import "../../../../../../node_modules/echarts/map/js/province/xinjiang";
  40. import "../../../../../../node_modules/echarts/map/js/province/xizang";
  41. import "../../../../../../node_modules/echarts/map/js/province/yunnan";
  42. import "../../../../../../node_modules/echarts/map/js/province/zhejiang";
  43. import * as echarts from "echarts";
  44. import "../../../../../../node_modules/echarts/map/js/china.js";
  45. //https://www.makeapie.com/editor.html?c=x2yaz6dfRw
  46. //https://www.makeapie.com/editor.html?c=xMpGBbTEKU
  47. let geoCoordMap = {
  48. 台湾省: [121.5135, 25.0308],
  49. 黑龙江省: [127.9688, 45.368],
  50. 内蒙古自治区: [110.3467, 41.4899],
  51. 吉林省: [125.8154, 44.2584],
  52. 北京市: [116.4551, 40.2539],
  53. 辽宁省: [123.1238, 42.1216],
  54. 河北省: [114.4995, 38.1006],
  55. 天津市: [117.4219, 39.4189],
  56. 山西省: [112.3352, 37.9413],
  57. 陕西省: [109.1162, 34.2004],
  58. 甘肃省: [103.5901, 36.3043],
  59. 宁夏回族自治区: [106.3586, 38.1775],
  60. 青海省: [101.4038, 36.8207],
  61. 新疆维吾尔自治区: [87.9236, 43.5883],
  62. 西藏自治区: [91.11, 29.97],
  63. 四川省: [103.9526, 30.7617],
  64. 重庆市: [108.384366, 30.439702],
  65. 山东省: [117.1582, 36.8701],
  66. 河南省: [113.4668, 34.6234],
  67. 江苏省: [118.8062, 31.9208],
  68. 安徽省: [117.29, 32.0581],
  69. 湖北省: [114.3896, 30.6628],
  70. 浙江省: [119.5313, 29.8773],
  71. 福建省: [119.4543, 25.9222],
  72. 江西省: [116.0046, 28.6633],
  73. 湖南省: [113.0823, 28.2568],
  74. 贵州省: [106.6992, 26.7682],
  75. 云南省: [102.9199, 25.4663],
  76. 广东省: [113.12244, 23.009505],
  77. 广西壮族自治区: [108.479, 23.1152],
  78. 海南省: [110.3893, 19.8516],
  79. 上海市: [121.4648, 31.2891],
  80. 香港: [114.173355, 22.320048],
  81. 澳门: [113.54909, 22.198951],
  82. };
  83. let data = [
  84. {
  85. name: "南海诸岛",
  86. value: 1,
  87. },
  88. {
  89. name: "北京",
  90. value: 524,
  91. },
  92. {
  93. name: "天津",
  94. value: 14,
  95. },
  96. {
  97. name: "上海",
  98. value: 150,
  99. },
  100. {
  101. name: "重庆",
  102. value: 75,
  103. },
  104. {
  105. name: "河北",
  106. value: 13,
  107. },
  108. {
  109. name: "河南",
  110. value: 83,
  111. },
  112. {
  113. name: "云南",
  114. value: 11,
  115. },
  116. {
  117. name: "辽宁",
  118. value: 19,
  119. },
  120. {
  121. name: "黑龙江",
  122. value: 15,
  123. },
  124. {
  125. name: "湖南",
  126. value: 69,
  127. },
  128. {
  129. name: "安徽",
  130. value: 260,
  131. },
  132. {
  133. name: "山东",
  134. value: 39,
  135. },
  136. {
  137. name: "新疆",
  138. value: 4,
  139. },
  140. {
  141. name: "江苏",
  142. value: 31,
  143. },
  144. {
  145. name: "浙江",
  146. value: 104,
  147. },
  148. {
  149. name: "江西",
  150. value: 36,
  151. },
  152. {
  153. name: "湖北",
  154. value: 1052,
  155. },
  156. {
  157. name: "广西",
  158. value: 33,
  159. },
  160. {
  161. name: "甘肃",
  162. value: 347,
  163. },
  164. {
  165. name: "山西",
  166. value: 8,
  167. },
  168. {
  169. name: "内蒙古",
  170. value: 157,
  171. },
  172. {
  173. name: "陕西",
  174. value: 22,
  175. },
  176. {
  177. name: "吉林",
  178. value: 4,
  179. },
  180. {
  181. name: "福建",
  182. value: 36,
  183. },
  184. {
  185. name: "贵州",
  186. value: 39,
  187. },
  188. {
  189. name: "广东",
  190. value: 996,
  191. },
  192. {
  193. name: "青海",
  194. value: 27,
  195. },
  196. {
  197. name: "西藏",
  198. value: 31,
  199. },
  200. {
  201. name: "四川",
  202. value: 46,
  203. },
  204. {
  205. name: "宁夏",
  206. value: 16,
  207. },
  208. {
  209. name: "海南",
  210. value: 22,
  211. },
  212. {
  213. name: "台湾",
  214. value: 6,
  215. },
  216. {
  217. name: "香港",
  218. value: 2,
  219. },
  220. {
  221. name: "澳门",
  222. value: 9,
  223. },
  224. ];
  225. let convertData = function (data) {
  226. let res = [];
  227. for (let i = 0; i < data.length; i++) {
  228. let geoCoord = geoCoordMap[data[i].name];
  229. if (geoCoord) {
  230. res.push({
  231. name: data[i].name,
  232. value: geoCoord.concat(data[i].value),
  233. });
  234. }
  235. }
  236. return res;
  237. };
  238. let max = 6000,
  239. min = 10;
  240. let maxSize4Pin = 100,
  241. minSize4Pin = 20;
  242. import {eventBusParams} from "@/utils/screen";
  243. export default {
  244. name: "widgetAirBubbleMap",
  245. props: {
  246. value: Object,
  247. ispreview: Boolean,
  248. },
  249. data() {
  250. return {
  251. options: {
  252. //backgroundColor: '#0F1C3C',
  253. tooltip: {
  254. trigger: "item",
  255. formatter: function (params) {
  256. if (params.value.length > 1) {
  257. return params.data.name + "" + params.data.value[2];
  258. } else {
  259. return params.name;
  260. }
  261. },
  262. },
  263. geo: {
  264. map: "china",
  265. show: true,
  266. roam: true,
  267. label: {
  268. emphasis: {
  269. show: false,
  270. },
  271. },
  272. layoutSize: "80%",
  273. itemStyle: {
  274. normal: {
  275. borderColor: new echarts.graphic.LinearGradient(
  276. 0,
  277. 0,
  278. 0,
  279. 1,
  280. [
  281. {
  282. offset: 0,
  283. color: "#00F6FF",
  284. },
  285. {
  286. offset: 1,
  287. color: "#53D9FF",
  288. },
  289. ],
  290. false
  291. ),
  292. borderWidth: 1,
  293. shadowColor: "rgba(10,76,139,1)",
  294. shadowOffsetY: 0,
  295. shadowBlur: 60,
  296. },
  297. },
  298. },
  299. series: [
  300. {
  301. type: "effectScatter",
  302. coordinateSystem: "geo",
  303. rippleEffect: {
  304. brushType: "stroke",
  305. },
  306. showEffectOn: "render",
  307. itemStyle: {
  308. normal: {
  309. //气泡颜色
  310. color: {
  311. type: "radial",
  312. x: 0.5,
  313. y: 0.5,
  314. r: 0.5,
  315. colorStops: [
  316. {
  317. offset: 0,
  318. color: "rgba(5,80,151,0.2)",
  319. },
  320. {
  321. offset: 0.8,
  322. color: "rgba(5,80,151,0.8)",
  323. },
  324. {
  325. offset: 1,
  326. color: "rgba(0,108,255,0.7)",
  327. },
  328. ],
  329. global: false,
  330. },
  331. },
  332. },
  333. label: {
  334. normal: {
  335. show: true,
  336. color: "#fff",
  337. fontWeight: "bold",
  338. position: "inside",
  339. formatter: function (para) {
  340. return "{cnNum|" + para.data.value[2] + "}";
  341. },
  342. rich: {
  343. cnNum: {
  344. fontSize: 13,
  345. color: "#D4EEFF",
  346. },
  347. },
  348. },
  349. },
  350. symbol: "circle",
  351. symbolSize: function (val) {
  352. if (val[2] == 0) {
  353. return 0;
  354. }
  355. return (
  356. ((maxSize4Pin - minSize4Pin) / (max - min)) * val[2] +
  357. (maxSize4Pin -
  358. ((maxSize4Pin - minSize4Pin) / (max - min)) * max) *
  359. 1.2
  360. );
  361. },
  362. data: convertData(data),
  363. zlevel: 1,
  364. },
  365. ],
  366. },
  367. optionsStyle: {}, // 样式
  368. optionsData: {}, // 数据
  369. optionsCollapse: {}, // 图标属性
  370. optionsSetup: {},
  371. flagInter: null,
  372. };
  373. },
  374. computed: {
  375. styleObj() {
  376. return {
  377. position: this.ispreview ? "absolute" : "static",
  378. width: this.optionsStyle.width + "px",
  379. height: this.optionsStyle.height + "px",
  380. left: this.optionsStyle.left + "px",
  381. top: this.optionsStyle.top + "px",
  382. background: this.optionsSetup.background,
  383. };
  384. },
  385. allComponentLinkage() {
  386. return this.$store.state.designer.allComponentLinkage;
  387. },
  388. },
  389. watch: {
  390. value: {
  391. handler(val) {
  392. this.optionsStyle = val.position;
  393. this.optionsData = val.data;
  394. this.optionsCollapse = val.setup;
  395. this.optionsSetup = val.setup;
  396. this.editorOptions();
  397. },
  398. deep: true,
  399. },
  400. },
  401. mounted() {
  402. this.optionsStyle = this.value.position;
  403. this.optionsData = this.value.data;
  404. this.optionsCollapse = this.value.setup;
  405. this.optionsSetup = this.value.setup;
  406. this.editorOptions();
  407. eventBusParams(
  408. this.optionsSetup,
  409. this.optionsData,
  410. (dynamicData, optionsSetup) => {
  411. this.getEchartData(dynamicData, optionsSetup);
  412. }
  413. );
  414. targetWidgetLinkageLogic(this); // 联动-目标组件逻辑
  415. },
  416. methods: {
  417. // 修改图标options属性
  418. editorOptions() {
  419. this.setOptionsTitle();
  420. this.setOptionsGeo();
  421. this.setOptionsData();
  422. this.setOptionAirSize();
  423. this.setOptionsTooltip();
  424. },
  425. // 标题设置
  426. setOptionsTitle() {
  427. const optionsSetup = this.optionsSetup;
  428. const title = {
  429. text: optionsSetup.text,
  430. show: optionsSetup.isShowTitle,
  431. left: optionsSetup.titleLeft,
  432. top: optionsSetup.titleTop + "%",
  433. itemGap: optionsSetup.titleItemGap,
  434. textStyle: {
  435. color: optionsSetup.textColor,
  436. fontSize: optionsSetup.textFontSize,
  437. fontWeight: optionsSetup.textFontWeight,
  438. fontStyle: optionsSetup.textFontStyle,
  439. fontFamily: optionsSetup.textFontFamily,
  440. },
  441. subtext: optionsSetup.subtext,
  442. subtextStyle: {
  443. color: optionsSetup.subtextColor,
  444. fontWeight: optionsSetup.subtextFontWeight,
  445. fontSize: optionsSetup.subtextFontSize,
  446. fontStyle: optionsSetup.subtextFontStyle,
  447. fontFamily: optionsSetup.subtextFontFamily
  448. },
  449. };
  450. this.options.title = title;
  451. },
  452. setOptionsGeo() {
  453. const optionsSetup = this.optionsSetup;
  454. const geo = {
  455. map: this.optionsSetup.mapName == '' ? "china" : this.optionsSetup.mapName,
  456. show: true,
  457. roam: true,
  458. layoutSize: "80%",
  459. label: {
  460. //调整数值
  461. // 地图省市区显隐
  462. show: optionsSetup.isShowMap,
  463. color: optionsSetup.fontColor,
  464. fontSize: optionsSetup.fontSize,
  465. fontWeight: optionsSetup.fontWeight,
  466. fontStyle: optionsSetup.fontStyle,
  467. fontFamily: optionsSetup.fontFamily,
  468. },
  469. itemStyle: {
  470. normal: {
  471. //地图块颜色
  472. areaColor: {
  473. x: 0,
  474. y: 0,
  475. x2: 0,
  476. y2: 1,
  477. colorStops: [
  478. {
  479. offset: 0,
  480. color: optionsSetup.fontColor0, // 0% 处的颜色
  481. },
  482. {
  483. offset: 1,
  484. color: optionsSetup.fontColor100, // 100% 处的颜色
  485. },
  486. ],
  487. },
  488. borderType: optionsSetup.borderType,
  489. borderColor: optionsSetup.borderColor,
  490. borderWidth: optionsSetup.borderWidth,
  491. shadowColor: optionsSetup.shadowColor,
  492. shadowBlur: optionsSetup.shadowBlur,
  493. opacity: optionsSetup.opacity / 100,
  494. },
  495. },
  496. //鼠标放置颜色加深
  497. emphasis: {
  498. label: {
  499. show: optionsSetup.isShowEmphasisLabel,
  500. color: optionsSetup.emphasisLabelFontColor,
  501. fontSize: optionsSetup.emphasisLabelFontSize,
  502. fontWeight: optionsSetup.emphasisLabelFontWeight,
  503. fontStyle: optionsSetup.emphasisLabelFontStyle,
  504. fontFamily: optionsSetup.emphasisLabelFontFamily,
  505. },
  506. itemStyle: {
  507. areaColor: {
  508. x: 0,
  509. y: 0,
  510. x2: 0,
  511. y2: 1,
  512. colorStops: [
  513. {
  514. offset: 0,
  515. color: optionsSetup.emphasisLabelFontColor0, // 0% 处的颜色
  516. },
  517. {
  518. offset: 1,
  519. color: optionsSetup.emphasisLabelFontColor100, // 100% 处的颜色
  520. },
  521. ],
  522. },
  523. },
  524. },
  525. }
  526. this.options.geo = geo;
  527. },
  528. setOptionAirSize() {
  529. maxSize4Pin = this.optionsSetup.fontmaxSize4Pin;
  530. minSize4Pin = this.optionsSetup.fontminSize4Pin;
  531. },
  532. // tooltip 设置
  533. setOptionsTooltip() {
  534. const optionsSetup = this.optionsSetup;
  535. const tooltip = {
  536. trigger: "item",
  537. show: optionsSetup.isShowTooltip,
  538. backgroundColor: optionsSetup.tooltipBackgroundColor,
  539. borderColor: optionsSetup.tooltipBorderColor,
  540. borderWidth: optionsSetup.tooltipBorderWidth,
  541. textStyle: {
  542. color: optionsSetup.tooltipColor,
  543. fontSize: optionsSetup.tooltipFontSize,
  544. fontWeight: optionsSetup.tooltipFontWeight,
  545. fontStyle: optionsSetup.tooltipFontStyle,
  546. fontFamily: optionsSetup.tooltipFontFamily,
  547. },
  548. formatter: function (params) {
  549. if (params.value.length > 1) {
  550. return params.data.name + " " + params.data.value[2];
  551. } else {
  552. return params.name;
  553. }
  554. },
  555. };
  556. this.options.tooltip = tooltip;
  557. },
  558. //数据解析
  559. setOptionsData(e, paramsConfig) {
  560. const optionsData = this.optionsData; // 数据类型 静态 or 动态
  561. // 联动接收者逻辑开始
  562. optionsData.dynamicData = optionsData.dynamicData || {}; // 兼容 dynamicData undefined
  563. const myDynamicData = optionsData.dynamicData;
  564. clearInterval(this.flagInter); // 不管咋,先干掉上一次的定时任务,避免多跑
  565. if (
  566. e &&
  567. optionsData.dataType !== "staticData" &&
  568. Object.keys(myDynamicData.contextData).length
  569. ) {
  570. const keyArr = Object.keys(myDynamicData.contextData);
  571. paramsConfig.forEach((conf) => {
  572. if (keyArr.includes(conf.targetKey)) {
  573. myDynamicData.contextData[conf.targetKey] = e[conf.originKey];
  574. }
  575. });
  576. }
  577. // 联动接收者逻辑结束
  578. optionsData.dataType == "staticData"
  579. ? this.staticDataFn(optionsData.staticData)
  580. : this.dynamicDataFn(optionsData.dynamicData, optionsData.refreshTime);
  581. },
  582. staticDataFn(val) {
  583. const optionsSetup = this.optionsSetup;
  584. const label = this.options.series[0]["label"];
  585. const normal = {
  586. show: optionsSetup.isShowData,
  587. color: "#fff",
  588. fontWeight: "bold",
  589. position: "inside",
  590. formatter: function (para) {
  591. return "{cnNum|" + para.data.value[2] + "}";
  592. },
  593. rich: {
  594. cnNum: {
  595. fontSize: optionsSetup.fontDataSize,
  596. color: optionsSetup.fontDataColor,
  597. fontWeight: optionsSetup.fontDataWeight,
  598. fontStyle: optionsSetup.fontDataStyle,
  599. fontFamily: optionsSetup.fontDataFamily,
  600. },
  601. },
  602. };
  603. const data = convertData(val);
  604. this.options.series[0]["data"] = data;
  605. label["normal"] = normal;
  606. },
  607. dynamicDataFn(val, refreshTime) {
  608. if (!val) return;
  609. if (this.ispreview) {
  610. this.getEchartData(val);
  611. this.flagInter = setInterval(() => {
  612. this.getEchartData(val);
  613. }, refreshTime);
  614. } else {
  615. this.getEchartData(val);
  616. }
  617. },
  618. getEchartData(val) {
  619. const data = this.queryEchartsData(val);
  620. data.then((res) => {
  621. this.renderingFn(res);
  622. });
  623. },
  624. renderingFn(val) {
  625. const optionsSetup = this.optionsSetup;
  626. const label = this.options.series[0]["label"];
  627. const normal = {
  628. show: optionsSetup.isShowData,
  629. color: "#fff",
  630. fontWeight: "bold",
  631. position: "inside",
  632. formatter: function (para) {
  633. return "{cnNum|" + para.data.value[2] + "}";
  634. },
  635. rich: {
  636. cnNum: {
  637. fontSize: optionsSetup.fontDataSize,
  638. color: optionsSetup.fontDataColor,
  639. fontWeight: optionsSetup.fontDataWeight,
  640. fontStyle: optionsSetup.fontDataStyle,
  641. fontFamily: optionsSetup.fontDataFamily,
  642. },
  643. },
  644. };
  645. const data = convertData(val);
  646. this.options.series[0]["data"] = data;
  647. label["normal"] = normal;
  648. },
  649. },
  650. };
  651. </script>
  652. <style lang="scss" scoped>
  653. .echartMap {
  654. width: 100%;
  655. height: 100%;
  656. }
  657. .echarts {
  658. width: 100%;
  659. height: 100%;
  660. overflow: hidden;
  661. }
  662. </style>