以前写过 vue项目中封装echarts的比较优雅的方式vue2项目中封装echarts地图比较优雅的方式,这次对地图做一个小拓展,在vue2项目中封装echarts地图比较优雅的方式 的基础上进行。

能学到的知识

  • 1、echarts地图背景图设置,可以设置随意的地图纹理
  • 2、echarts地图打点,显示数据

效果图

虽然不明显,但是打点是真的在闪动的

在这里插入图片描述

实现

vue2项目中封装echarts地图比较优雅的方式 的基础上稍微做点改变。

echarts地图模块封装

|-- src
    |-- components
        |-- chart
            |-- options    // 存放各种图表的option
                |-- map    // 地图option
                    |-- index.js

具体代码如下:

// import echarts from 'echarts'
import * as echarts from 'echarts'
import mapbg from '@/assets/images/map-bg.png'

const getSimpleMap = (jsonMap, data, config) => {
  if (!echarts.getMap(jsonMap.mark)) {
    echarts.registerMap(jsonMap.mark, jsonMap.json)
  }
  const convertData = (data) => {
    console.log(data)
    var res = []
    for (var i = 0; i < data.length; i++) {
      const mapData = data[i].hoverObj
      const center = data[i].mapProperty.center

      if (center && mapData) {
        res.push({
          name: mapData.name,
          value: center.concat(mapData.num)
        })
      }
    }
    return res
  }
  const defaultConfig = {
    tooltip: {
      // 窗口外框
      trigger: 'item',
      padding: 0,
      borderWidth: 0,
      borderColor: '#FFFFFF',
      backgroundColor: '#FFFFFF',
      formatter: (params) => {
        const { data } = params
        const str = `<div style="width:300px;height: 98px;box-shadow: 0px 4px 20px 0px rgba(0, 0, 0, 0.8);
                    color: #fff;text-align:left;border-radius: 6px;">
                    <div style="background-color: rgba(102, 182, 255, 1);height: 44px;line-height: 44px;font-size:14px;font-weight:400;border-top-left-radius: 6px;border-top-right-radius: 6px;display: flex;align-items: center;">
                        <img style="width: 13px;height:16px;margin-left: 24px;margin-right: 3px;" src="images/map-ic.png">${data.name}
                    </div>
                    <div style="width: 100%;height:54px;display: flex;flex-wrap: wrap;">
                        <div style="display: flex;justify-content: space-between;width: 100%;padding-left:15px;padding-right: 15px;">
                            <div style="display:flex;align-items:center;width:132px;">
                                <div style="font-size: 12px;color: #555555;margin-right:10px;">区号:</div>
                                <div style="font-size: 14px;color: #333333;">${data.hoverObj == null ? '' : data.hoverObj.adcode}</div>
                            </div>
                        </div>
                    </div>
                </div>`
        return str
      }
    },
    geo: {
      map: jsonMap.mark,
      type: 'map',
      layoutCenter: ['50%', '50%'],
      layoutSize: '150%',
      zoom: 0.65,
      roam: false,
      // 样式一
      // itemStyle: {
      //   normal: {
      //     areaColor: 'rgba(13, 110, 191, 1)',
      //     shadowColor: 'rgba(13, 110, 191, 0.5)',
      //     shadowOffsetX: 6,
      //     shadowOffsetY: 12
      //   }
      // }
      // 样式二
      itemStyle: {
        normal: {
          borderColor: '#AEF3FF',
          borderWidth: 2,
          areaColor: {
            image: mapbg, //
            repeat: 'repeat' // // 是否平铺,可以是 'repeat-x', 'repeat-y', 'no-repeat'
          },
          shadowColor: 'rgba(13, 110, 191, 0.5)',
          shadowOffsetX: 6,
          shadowOffsetY: 12
        }
      }
    },
    series: [
      {
        type: 'map',
        map: jsonMap.mark, // 自定义扩展图表类型
        zoom: 0.65, // 缩放
        animationDuration: 1200,
        // 点击选中后的效果
        select: {
          label: {
            color: '#FFFFFF',
            fontSize: 12,
            fontWeight: 400
          },
          // 清除点击选中后的背景色
          itemStyle: {
            color: null
          }
        },
        // 样式一
        // itemStyle: {
        //   // 地图样式
        //   normal: {
        //     borderColor: '#FFFFFF',
        //     borderWidth: 3,
        //     areaColor: 'rgba(201, 229, 255, 1)'
        //   }
        // },
        // 样式二
        itemStyle: {
          // 地图样式
          normal: {
            borderColor: '#AEF3FF',
            borderWidth: 2,
            areaColor: {
              image: mapbg, //
              repeat: 'repeat' // // 是否平铺,可以是 'repeat-x', 'repeat-y', 'no-repeat'
            }
          }
        },
        // 样式一
        // label: {
        //   show: true,
        //   color: '#666666',
        //   fontSize: 12,
        //   fontWeight: 400
        // },
        // 样式二
        label: {
          show: true,
          color: '#FFFFFF',
          fontSize: 12,
          fontWeight: 400
        },
        emphasis: {
          // 鼠标移入动态的时候显示的默认样式
          label: {
            show: true,
            color: '#FFFFFF',
            fontSize: 15,
            fontWeight: 600
          },
          itemStyle: {
            areaColor: 'rgba(102, 182, 255, 0.7)',
            borderColor: '#FFFFFF',
            borderWidth: 2
          }
        },
        layoutCenter: ['50%', '50%'],
        layoutSize: '150%',
        data: data
      },
      {
        type: 'effectScatter',
        coordinateSystem: 'geo',
        symbol: 'image://data:image/png;base64,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',
        symbolSize: [16, 16],
        // symbolOffset: [],
        label: {
          normal: {
            show: true,
            offset: [0, -18],
            textStyle: {
              color: '#fff',
              fontSize: 12,
              fontWeight: 500
            },
            formatter(value) {
              return '{a|' + value.data.value[2] + '}'
            },
            rich: {
              a: {
                color: '#FFFFFF',
                backgroundColor: '#06406A',
                width: 28,
                height: 16,
                lineHeight: 16,
                align: 'center',
                borderWidth: 1,
                borderColor: '#79D6FE',
                borderRadius: 2,
                padding: [0, 4, 0, 4]
              }
            }
          }
        },
        itemStyle: {
          normal: {
            color: 'rgba(255, 178, 76, 1)'
          }
        },
        data: convertData(data),
        showEffectOn: 'render',
        rippleEffect: {
          brushType: 'stroke'
        },
        hoverAnimation: true,
        zlevel: 9
      }
    ]
  }
  const opt = Object.assign({}, defaultConfig, config)
  const { legend, tooltip, series, geo, grid } = opt
  const chartOpt = {
    grid,
    legend,
    tooltip,
    geo,
    series
  }
  return chartOpt
}

export default {
  getSimpleMap
}

新增的代码,最好在Visual Studio CodeTimeline里面对比查看,只是添加了地图纹理和地图打点。

地图纹理 (components–chart–options–map–index.js)

实现代码在:

  • geo样式二的itemStyle,这里控制鼠标移入地图模块时的纹理
  • series样式二的itemStyle,这里控制地图默认状态下的纹理
地图打点 (components–chart–options–map–index.js)

实现代码在effectScatter模块,主要是自定义了打点的图标,还有自定义了显示信息的label的样式,这里可以根据设计随意实现。

打点数据在convertData方法里面处理,可以根据接口数据看着办。

数据 (views–echartMapTest–index.js)

因为要在地图上打点,需要坐标,加载数据的时候,需要加上地图的坐标,主要是加上这一行,properties包含了地图所有基本数据了

mapProperty: item.properties

具体如下:

initMap(url) {
      mapRequest(url).then((res) => {
        const mapData = res.data
        const jsonMap = { mark: this.mapName, json: mapData }

        const data = mapData.features.map((item) => {
          const { name, adcode } = item.properties

          let hoverObj = {}

          const objIndex = this.$utils.findElem(this.mapPopData, 'adcode', adcode)
          if (objIndex !== -1) {
            hoverObj = this.mapPopData[objIndex]
          } else {
            hoverObj = null
          }
          return {
            name,
            mapProperty: item.properties,
            hoverObj: hoverObj
          }
        })
        this.mapOpt = this.$eChartFn.getSimpleMap(jsonMap, data)
      }).catch((err) => {
        console.log(err, '加载地图失败')
      })
    }

代码总览

涉及的文件如下(具体参考代码):

|-- public
	|-- data
		|-- 4401.json
		|-- mapdata.json
|-- src
	|-- api
		|-- map.js    // 获取地图geojson数据、地图弹窗接口模拟数据
    |-- components
        |-- chart
            |-- index.vue    // 图表单文件组件,供界面调用
            |-- index.js    // 实现自动化导入options里的图表option
            |-- options    // 存放各种图表的option
                |-- map    // 地图option
                    |-- index.js
    |-- views
        |-- echartMapTest    // 实例所在
            |-- index.vue
            |-- index.scss
            |-- index.js
	|-- utils
		|---utils.js
|-- main.js    // 全局引入echarts图表

代码

代码总览的目录去代码里找着看就行了。

总结

echarts地图的纹理不只可以纯色或者渐变色的,还可以根据设计随意设置。项目中UI设计的很好看,这里只是随意截取了纹理的一部分做了个例子。

以上,基本只要UI设计的出来,就可以实现任意纹理样式的地图。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐