使用ECharts渲染地图,添加图片作为地图纹理,自定义弹窗

559 阅读6分钟

image.png

1.通过阿里云数据可视化平台设置行政区范围,下载geoJson数据文件,在代码中引入该地图数据文件。

阿里云数据可视化平台:点击跳转

image.png

2.使用ECharts渲染地图,添加图片作为地图纹理。

地图背景图:

image.png

效果图:

image.png

注意问题:

如果在渲染地图时,发现背景渲染比较模糊:

  • 检查ECharts 版本,ECharts 4.x 对纹理渲染存在缺陷,导致背景模糊。可以考虑升级到更高版本。目前已知4.2.1是有问题的,我本地升级到5.4.3后正常,且在4.2.1版本下通过以下方法,也无法解决图片模糊的问题。

  • 容器尺寸与图片分辨率需要匹配,可以调整layoutSize和容器的尺寸,使得图片不需要被过度缩放;

  • 检查图片分辨率,确保使用更高分辨率的图片,以便在放大的情况下也能清晰显示。

  • 平铺模式(repeat)不匹配, repeat支持设置'no-repeat','repeat','repeat-x', 'repeat-y',可以根据实际效果进行调整;

如果在渲染地图时,发现背景图纹理不显示:

检查图片是否未预加载完成,确保在图片加载完成后,再执行图表的初始化。

如果在渲染地图时,发现地图拖拽会分层:

检查series的geoIndex属性,通过指定geoIndex,使map 和 series共享一个geo;

代码(以下代码不包含弹窗效果):

<template>
  <div id="myChart" />
</template>
<script>
import * as echarts from 'echarts'
import chinaJson from './china.json'
export default {
  name: 'LabMap',
  data() {
    return {}
  },
  mounted() {
    this.initChart()
  },
  methods: {
    initChart() {
      const domImg = document.createElement('img')
      domImg.src = require('./mapBg.png')
      const myChart = echarts.init(document.getElementById('myChart'))
      myChart.showLoading()
      echarts.registerMap('china', chinaJson) // 注册中国地图
      myChart.hideLoading()
      const option = {
        backgroundColor: '#040b1c',
        geo: {
          show: true, // 是否显示地理坐标系组件
          map: 'china', // 使用 registerMap 注册的地图名称
          roam: true, // 是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启
          zoom: 0.9, // 固定缩放
          layoutCenter: ['50%', '50%'], // 地图中心在屏幕中的位置
          layoutSize: '100%', // 地图的大小,支持相对于屏幕宽高的百分比或者绝对的像素大小
          aspectScale: 0.75, // 这个参数用于 scale 地图的长宽比,如果设置了projection则无效
          label: {
            show: false, // 是否显示标签
            emphasis: {
              // 高亮状态下的多边形和标签样式
              show: false
            }
          },
          itemStyle: {
            areaColor: { // 地图区域的颜色(支持纯色,渐变色或者纹理填充,image为纹理填充)
              image: domImg, // 支持为 HTMLImageElement, HTMLCanvasElement,不支持路径字符串
              repeat: 'repeat' // 是否平铺,可以是 'repeat-x', 'repeat-y', 'no-repeat'
            },
            borderColor: '#5CDDF7', // 图形的描边颜色
            borderWidth: 2, // 描边线宽。为 0 时无描边。
            shadowBlur: 10, // 图形阴影的模糊大小。该属性配合 shadowColor,shadowOffsetX, shadowOffsetY 一起设置图形的阴影效果。
            shadowColor: '#5CDDF7', // 阴影颜色
            shadowOffsetX: -5, // 阴影水平方向上的偏移距离
            shadowOffsetY: 5, // 阴影垂直方向上的偏移距离
            emphasis: { // 高亮状态下的多边形和标签样式
              areaColor: '#18FEFE',
              borderColor: 'yellow'
            }
          }
        },
        series: [
          {
            name: '数据',
            type: 'map',
            map: 'china', // 使用注册的地图名称
            geoIndex: 0, // 0不会分层
            label: {
              show: false // 显示省份名称
            },
            // 确保纹理层级正确:将纹理仅应用于 geo 组件,避免与 series 冲突:
            itemStyle: {
              areaColor: 'transparent' // 系列设置为透明,透出geo的纹理
            },
            data: [
              { name: '北京', value: 100 },
              { name: '上海', value: 200 }
            ]
          }
        ]
      }
      myChart.clear()
      myChart.setOption(option)
      window.addEventListener(
        'resize',
        () => {
          myChart.resize()
        },
        false
      )
    }
  }
}
</script>

<style scoped>
#myChart {
  width: 80%;
  height: 800px;
  margin: auto;
}
</style>

3.添加弹窗,优化展示效果

  • 高亮选中区域,优化鼠标悬浮效果;
  • 增加坐标弹窗,自定义展示效果;
  • 增加坐标点图标,图标跳动显示;

image.png

完整代码

<template>
  <div id="myChart" />
</template>
<script>
import * as echarts from 'echarts'
import chinaJson from './china.json'
export default {
  name: 'LabMap',
  data() {
    return {}
  },
  mounted() {
    this.initChart()
  },
  methods: {
    initChart() {
      const data = [
        {
          deviceCount: 138,
          longitude: '110.3467',
          latitude: '41.4899',
          region: '内蒙古',
          remark: '测试数据测试数据测试数据测试数据测试数据'
        },
        {
          deviceCount: 235,
          longitude: '91.11',
          latitude: '29.97',
          region: '西藏',
          remark: '测试数据测试数据测试数据测试数据测试数据'
        },
        {
          deviceCount: 400,
          longitude: '113.0823',
          latitude: '28.2568',
          region: '湖南',
          remark: '测试数据测试数据测试数据测试数据测试数据'
        }
      ]
      const regionData = []
      const ponitData = []
      data.forEach((item) => {
        regionData.push({
          name: item.region,
          value: [Number(item.longitude), Number(item.latitude)]
        })
        ponitData.push({
          name: item.region,
          deviceCount: item.deviceCount,
          value: [Number(item.longitude), Number(item.latitude)],
          remark: item.remark
        })
      })
      const domImg = document.createElement('img')
      domImg.src = require('./mapBg.png')
      const myChart = echarts.init(document.getElementById('myChart'))
      myChart.showLoading()
      echarts.registerMap('china', chinaJson) // 注册中国地图
      myChart.hideLoading()
      const option = {
        backgroundColor: '#040b1c',
        tooltip: {
          trigger: 'item',
          backgroundColor: '#002260',
          borderColor: '#0984F3',
          color: '#fff',
          borderWidth: 1,
          padding: [5, 15],
          textStyle: {
            color: '#fff'
          },
          formatter: '{b}'
        },
        geo: {
          show: true, // 是否显示地理坐标系组件
          map: 'china', // 使用 registerMap 注册的地图名称
          roam: true, // 是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启
          zoom: 0.9, // 固定缩放
          layoutCenter: ['50%', '50%'], // 地图中心在屏幕中的位置
          layoutSize: '100%', // 地图的大小,支持相对于屏幕宽高的百分比或者绝对的像素大小
          aspectScale: 0.75, // 这个参数用于 scale 地图的长宽比,如果设置了projection则无效
          label: {
            show: false, // 是否显示标签
            emphasis: {
              // 高亮状态下的多边形和标签样式
              show: false
            }
          },
          itemStyle: {
            areaColor: {
              // 地图区域的颜色(支持纯色,渐变色或者纹理填充,image为纹理填充)
              image: domImg, // 支持为 HTMLImageElement, HTMLCanvasElement,不支持路径字符串
              repeat: 'repeat' // 是否平铺,可以是 'repeat-x', 'repeat-y', 'no-repeat'
            },
            borderColor: '#5CDDF7', // 图形的描边颜色
            borderWidth: 2, // 描边线宽。为 0 时无描边。
            shadowBlur: 10, // 图形阴影的模糊大小。该属性配合 shadowColor,shadowOffsetX, shadowOffsetY 一起设置图形的阴影效果。
            shadowColor: '#5CDDF7', // 阴影颜色
            shadowOffsetX: -5, // 阴影水平方向上的偏移距离
            shadowOffsetY: 5, // 阴影垂直方向上的偏移距离
            emphasis: {
              // 高亮状态下的多边形和标签样式
              areaColor: '#0B2986',
              borderColor: '#0984F3'
            }
          }
        },
        series: [
          {
            symbolSize: 1,
            label: {
              normal: {
                formatter: '{b}',
                position: 'bottom',
                color: '#fff',
                fontSize: 16,
                fontWeight: 'bold',
                show: true
              },
              emphasis: {
                show: true
              }
            },
            name: '区域',
            type: 'scatter',
            coordinateSystem: 'geo',
            data: regionData
          },
          {
            name: '数据',
            type: 'map',
            map: 'china', // 使用注册的地图名称
            geoIndex: 0, // 0不会分层
            label: {
              show: false // 显示省份名称
            },
            // 确保纹理层级正确:将纹理仅应用于 geo 组件,避免与 series 冲突:
            itemStyle: {
              areaColor: 'transparent' // 系列设置为透明,透出geo的纹理
            },
            data: data
          },
          {
            name: '弹窗',
            type: 'effectScatter',
            coordinateSystem: 'geo',
            legendHoverLink: true,
            symbol: 'image://' + require('./坐标.png'),
            symbolSize: [15, 18],
            symbolOffset: ['-50%', '-70%'],
            data: ponitData,
            showEffectOn: 'render',
            rippleEffect: {
              period: 3, // 秒数
              scale: 3, // 缩放比例
              brushType: 'stroke'
            },
            hoverAnimation: true,
            zlevel: 1,
            label: {
              show: true,
              offset: [-95, 0], // 偏移设置
              lineHeight: 23,
              backgroundColor: '#002260',
              borderColor: '#5CDDF7',
              borderWidth: 1,
              padding: [4, 14],
              formatter: (value) => {
                let remark = value.data.remark
                remark =
                  remark.length > 6 ? remark.substr(0, 6) + '...' : remark
                return (
                  `{name|${value.data.name}}\n{pt|` +
                  '销售数量' +
                  `:}${value.data.deviceCount}` +
                  '台' +
                  `\n{pt|` +
                  '备注' +
                  `:}${remark}`
                )
              },
              rich: {
                name: {
                  color: '#fff'
                },
                pt: {
                  color: '#00CAFF'
                }
              },
              color: '#fff'
            }
          }
        ]
      }
      myChart.clear()
      myChart.setOption(option)
      window.addEventListener(
        'resize',
        () => {
          myChart.resize()
        },
        false
      )
    }
  }
}
</script>

<style scoped>
#myChart {
  width: 80%;
  height: 800px;
  margin: auto;
}
</style>