index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. <template>
  2. <div
  3. class="bs-design-wrap bs-bar"
  4. style="width: 100%; height: 100%"
  5. >
  6. <el-button v-if="currentDeep > 0" class="button" type='text' @click="jumpTo(config)"> 返回上一级</el-button>
  7. <div
  8. :id="`chart${config.code}`"
  9. style="width: 100%; height: 100%"
  10. />
  11. </div>
  12. </template>
  13. <script>
  14. import 'insert-css'
  15. import * as echarts from 'echarts'
  16. import commonMixins from 'data-room-ui/js/mixins/commonMixins.js'
  17. import paramsMixins from 'data-room-ui/js/mixins/paramsMixins'
  18. import linkageMixins from 'data-room-ui/js/mixins/linkageMixins'
  19. export default {
  20. name: 'MapCharts',
  21. mixins: [paramsMixins, commonMixins, linkageMixins],
  22. props: {
  23. id: {
  24. type: String,
  25. default: ''
  26. },
  27. config: {
  28. type: Object,
  29. default: () => ({})
  30. }
  31. },
  32. data() {
  33. return {
  34. currentDeep: 0,
  35. mapList: [],
  36. charts: null,
  37. hasData: false,
  38. level: '',
  39. option: {}
  40. }
  41. },
  42. computed: {
  43. Data() {
  44. return JSON.parse(JSON.stringify(this.config))
  45. }
  46. },
  47. watch: {
  48. Data: {
  49. handler(newVal, oldVal) {
  50. if (newVal.w !== oldVal.w || newVal.h !== oldVal.h) {
  51. this.$nextTick(() => {
  52. this.charts.resize()
  53. })
  54. }
  55. },
  56. deep: true
  57. }
  58. },
  59. mounted() {
  60. this.chartInit()
  61. },
  62. beforeDestroy() {
  63. this.charts?.clear()
  64. },
  65. methods: {
  66. chartInit() {
  67. const config = this.config
  68. // key和code相等,说明是一进来刷新,调用list接口
  69. if (this.config.code === this.config.key || this.isPreview) {
  70. // 改变数据
  71. this.changeDataByCode(config).then((res) => {
  72. // 改变样式
  73. // config = this.changeStyle(res)
  74. this.newChart(config)
  75. }).catch(() => {
  76. })
  77. } else {
  78. // 否则说明是更新,这里的更新只指更新数据(改变样式时是直接调取changeStyle方法),因为更新数据会改变key,调用chart接口
  79. this.changeData(config).then((res) => {
  80. // 初始化图表
  81. this.newChart(res)
  82. })
  83. }
  84. },
  85. dataFormatting(config, data) {
  86. const dataList = []
  87. data?.data?.forEach(item => {
  88. dataList.push({
  89. name: item[config.customize.name],
  90. value: [item[config.customize.xaxis], item[config.customize.yaxis], item[config.customize.value]]
  91. })
  92. })
  93. config.option = {
  94. ...config.option,
  95. data: dataList
  96. }
  97. return config
  98. },
  99. async jumpTo(config) {
  100. this.currentDeep--
  101. let map = this.mapList[this.currentDeep]
  102. // 移除mapList中的最后一个元素
  103. this.mapList.pop()
  104. let mapData = JSON.parse(map.geoJson)
  105. this.option.geo.map = map.name;
  106. this.changeData({...config, customize: {...config.customize, level: map.level, scope: map.name}})
  107. echarts.registerMap(map.name, mapData);
  108. this.charts.setOption(this.option, true);
  109. },
  110. async newChart(config) {
  111. let center1 = config.customize.center1 ? config.customize.center1 + '%' : '50%'
  112. let center2 = config.customize.center2 ? config.customize.center2 + '%' : '50%'
  113. this.charts = echarts.init(
  114. document.getElementById(`chart${this.config.code}`)
  115. )
  116. this.option = {
  117. // 背景颜色
  118. backgroundColor: config.customize.backgroundColor,
  119. graphic: [],
  120. geo: {
  121. map: config.customize.scope,
  122. zlevel: 9,
  123. show: true,
  124. // 地图中心点位置
  125. layoutCenter: [center1, center2],
  126. roam: true,
  127. layoutSize: "100%",
  128. zoom: config.customize.zoom || 1,
  129. label: {
  130. // 通常状态下的样式
  131. normal: {
  132. show: config.customize.mapName,
  133. textStyle: {
  134. color: '#fff'
  135. }
  136. },
  137. // 鼠标放上去的样式
  138. emphasis: {
  139. textStyle: {
  140. color: '#fff'
  141. }
  142. }
  143. },
  144. // 地图区域的样式设置
  145. itemStyle: {
  146. normal: {
  147. borderColor: config.customize.mapLineColor,
  148. borderWidth: 1,
  149. areaColor: config.customize.areaColor,
  150. shadowColor: 'fffff',
  151. shadowOffsetX: -2,
  152. shadowOffsetY: 2,
  153. shadowBlur: 10
  154. },
  155. // 鼠标放上去高亮的样式
  156. emphasis: {
  157. areaColor: '#389BB7',
  158. borderWidth: 0
  159. }
  160. }
  161. },
  162. // 提示浮窗样式
  163. tooltip: {
  164. show: false,
  165. trigger: 'item',
  166. alwaysShowContent: false,
  167. backgroundColor: config.customize.tooltipBackgroundColor,
  168. borderColor: config.customize.borderColor,
  169. hideDelay: 100,
  170. triggerOn: 'mousemove',
  171. enterable: true,
  172. textStyle: {
  173. color: '#DADADA',
  174. fontSize: '12',
  175. width: 20,
  176. height: 30,
  177. overflow: 'break'
  178. },
  179. showDelay: 100
  180. },
  181. series: config.customize.scatter
  182. ? [
  183. // {
  184. // type: 'effectScatter',
  185. // coordinateSystem: 'geo',
  186. // effectType: 'ripple',
  187. // showEffectOn: 'render',
  188. // rippleEffect: {
  189. // period: 10,
  190. // scale: 10,
  191. // brushType: 'fill'
  192. // },
  193. // hoverAnimation: true,
  194. // itemStyle: {
  195. // normal: {
  196. // color: 'rgba(255, 235, 59, .7)',
  197. // shadowBlur: 10,
  198. // shadowColor: '#333'
  199. // }
  200. // },
  201. // tooltip: {
  202. // formatter(params) {
  203. // return `<p style="text-align:center;line-height: 30px;height:30px;font-size: 14px;border-bottom: 1px solid #7A8698;">${
  204. // params.name
  205. // }</p>
  206. // <div style="line-height:22px;margin-top:5px">GDP<span style="margin-left:12px;color:#fff;float:right">${
  207. // params.data?.value[2] || '--'
  208. // }</span></div>`
  209. // },
  210. // show: true
  211. // },
  212. // zlevel: 1,
  213. // data: [
  214. // { name: '西藏自治区', value: [91.23, 29.5, 1] },
  215. // { name: '黑龙江省', value: [128.03, 47.01, 1007] },
  216. // { name: '北京市', value: [116.4551, 40.2539, 5007] }
  217. // ]
  218. // }
  219. {
  220. type: 'scatter',
  221. coordinateSystem: 'geo',
  222. symbol: 'pin',
  223. legendHoverLink: true,
  224. symbolSize: [60, 60],
  225. showEffectOn: 'render',
  226. rippleEffect: {
  227. brushType: 'stroke'
  228. },
  229. hoverAnimation: true,
  230. zlevel: 11,
  231. // 这里渲染标志里的内容以及样式
  232. label: {
  233. show: true,
  234. formatter(value) {
  235. return value.data.value[2]
  236. },
  237. color: config.customize.scatterColor
  238. },
  239. // 标志的样式
  240. itemStyle: {
  241. normal: {
  242. color: config.customize.scatterBackgroundColor,
  243. shadowBlur: 2,
  244. shadowColor: 'D8BC37'
  245. }
  246. },
  247. data: config.option?.data
  248. }
  249. ]
  250. : [
  251. {
  252. type: 'map',
  253. map: config.customize.scope,
  254. geoIndex: 0,
  255. roam: false,
  256. zoom: 1.5,
  257. center: [105, 36],
  258. showLegendSymbol: false, // 存在legend时显示
  259. data: config.option?.data,
  260. tooltip: {
  261. formatter(params) {
  262. return `<p style="text-align:center;line-height: 30px;height:30px;font-size: 14px;border-bottom: 1px solid #7A8698;">${
  263. params.name
  264. }</p>
  265. <div style="line-height:22px;margin-top:5px">GDP<span style="margin-left:12px;color:#fff;float:right">${
  266. params.data?.value[2] || '--'
  267. }</span></div>`
  268. },
  269. show: true
  270. }
  271. }
  272. ]
  273. }
  274. if (config.customize.visual) {
  275. this.option.visualMap = {
  276. show: true,
  277. min: config.customize.range[0],
  278. max: config.customize.range[1],
  279. seriesIndex: [0],
  280. inRange: {
  281. color: config.customize.rangeColor
  282. }
  283. }
  284. }
  285. let hasMapId = !!config.customize.mapId
  286. // 根据mapId获取地图数据
  287. let mapInfoUrl = `${window.BS_CONFIG?.httpConfigs?.baseURL}/bigScreen/map/info/${config.customize.mapId}`
  288. // 如果设置了地图id,就用地图id获取地图数据,否则用默认的世界地图
  289. if (!hasMapId) {
  290. mapInfoUrl = `${window.BS_CONFIG?.httpConfigs?.baseURL}/static/chinaMap/country/中华人民共和国.json`
  291. }
  292. const mapResp = await this.$dataRoomAxios.get(decodeURI(mapInfoUrl), {}, true)
  293. const map = hasMapId ? JSON.parse(mapResp.data.geoJson) : mapResp
  294. if (hasMapId && mapResp.data.uploadedGeoJson !== 1) {
  295. // 没有上传过geoJson
  296. this.$message({
  297. message: '请先上传地图数据',
  298. type: 'warning'
  299. })
  300. return
  301. }
  302. this.mapList.push(mapResp.data)
  303. echarts.registerMap(config.customize.scope, map)
  304. this.charts.setOption(this.option)
  305. // 点击下钻
  306. this.charts.on('click', async (params) => {
  307. if (params.name == '') return
  308. if (!config.customize.down) {
  309. this.$message({
  310. message: '该地图未开启下钻',
  311. type: 'warning'
  312. })
  313. return
  314. }
  315. // 到达允许下钻的层数,则不再下钻
  316. if (this.currentDeep >= config.customize.downLevel) return
  317. const downMapUrl = `${window.BS_CONFIG?.httpConfigs?.baseURL}/bigScreen/map/data/${this.mapList[this.currentDeep].id}/${params.name}`
  318. const downMap = await this.$dataRoomAxios.get(decodeURI(downMapUrl), {}, false)
  319. // 地图不可用
  320. if (downMap.available !== 1) {
  321. this.$message({
  322. message: '未找到该地图配置',
  323. type: 'warning'
  324. })
  325. return
  326. }
  327. this.currentDeep++
  328. this.mapList.push(downMap)
  329. this.changeData({...config, customize: {...config.customize, scope: params.name}})
  330. this.option.geo.map = params.name
  331. echarts.registerMap(params.name, JSON.parse(downMap.geoJson));
  332. this.charts.setOption(this.option, true);
  333. });
  334. }
  335. }
  336. }
  337. </script>
  338. <style lang="scss" scoped>
  339. @import '../../assets/style/echartStyle';
  340. .light-theme {
  341. background-color: #ffffff;
  342. color: #000000;
  343. }
  344. .auto-theme {
  345. background-color: rgba(0, 0, 0, 0);
  346. }
  347. .bs-design-wrap {
  348. position: relative;
  349. padding: 0 16px;
  350. .button {
  351. position: absolute;
  352. z-index: 999;
  353. }
  354. }
  355. </style>