vue 项目中使用 echarts 实现市区地图标注,地图下钻 ?

市区地图标注 


安装依赖

安装 echarts 和 echarts-gl 依赖 。

npm i echarts echarts-gl -S

新增 mapdata 资源包

assets 下新增 mapdata 资源包(中国个省市区县 json 文件),可以在网上自行查找下载,也可通过本文案例链接,在码云上拉取获得 。 完整示例链接https://gitee.com/wu241617/echarts-map

新建 map.json 文件

assets 下新增 config 目录,下新建 map.json 文件。我这里案例中只做了抚州市和荆州市的配置,后续有其他区域需要,新增添加即可 。文件中 coord 字段是对应 name 子区域的经纬度,可以在网上搜索查询,后续这里要进行微调,控制标注的位置 。
区域经纬度https://max.book118.com/html/2021/0507/6030102121003144.shtm

{
  "抚州市": {
    "geoJson": "/geometryCouties/361000.json",
    "qxwz": [
      {
        "name": "东乡区",
        "coord": [116.6, 28.18]
      },
      {
        "name": "临川区",
        "coord": [116.35, 27.98]
      },
      {
        "name": "金溪县",
        "coord": [116.75, 28]
      },
      {
        "name": "崇仁县",
        "coord": [116.05, 27.79]
      },
      {
        "name": "宜黄县",
        "coord": [116.25, 27.5]
      },
      {
        "name": "南城县",
        "coord": [116.66, 27.65]
      },
      {
        "name": "资溪县",
        "coord": [117.05, 27.8]
      },
      {
        "name": "乐安县",
        "coord": [115.83, 27.47]
      },
      {
        "name": "南丰县",
        "coord": [116.45, 27.24]
      },
      {
        "name": "黎川县",
        "coord": [116.85, 27.2]
      },
      {
        "name": "广昌县",
        "coord": [116.35, 26.87]
      }
    ]
  },
  "荆州市": {
    "geoJson": "/geometryCouties/421000.json",
    "qxwz": [
      {
        "name": "洪湖市",
        "coord": [113.59, 30.02]
      },
      {
        "name": "江陵县",
        "coord": [112.49, 30.01]
      },
      {
        "name": "荆州区",
        "coord": [112.08, 30.49]
      },
      {
        "name": "沙市区",
        "coord": [112.35, 30.41]
      },
      {
        "name": "松滋市",
        "coord": [111.62, 30.03]
      },
      {
        "name": "公安县",
        "coord": [112.12, 29.87]
      },
      {
        "name": "监利县",
        "coord": [112.96, 29.91]
      },
      {
        "name": "石首市",
        "coord": [112.51, 29.82]
      }
    ]
  }
}

组件案例

  • HTML:
<template>
  <div>
    <select v-model="selectCity"
      @change="cityChange"
      class="select">
      <option :label='item.name'
        :value="item.value"
        v-for="item in options"
        :key="item.value"></option>
    </select>
    <div class="selectedText">{{selectedText}}</div>
    <div class="mapMain"
      id="mapMain"></div>
  </div>
</template>
  • JS:

【注意】:地图配置中, geo 数组中有两个子项,渲染两个地图,通过控制 center 属性值配置,形成微错位,视觉上立体, 注意 center 值要处于当前区域经纬度之间,需要微调否则看不到地图渲染 ,其他具体配置请查看官方文档配置项。
官方文档https://echarts.apache.org/zh/option.html#title

import * as echarts from 'echarts';
import 'echarts-gl';
import { mapState } from 'vuex'

export default {
  name: 'Main',
  data() {
    return {
      selectCity: '361000',
      mapConfigJson: require("../../assets/config/map.json"),
      map: '',
      mapLoadCity: '',
      cityName: [],
      mapdataJson: [],
      selectedText: ''
    }
  },
  mounted() {
    this.cityChange();
  },
  computed: {
    ...mapState(['JZtestData', 'FZtestData', 'options'])
  },
  methods: {
    // 下拉框城市区域切换  
    cityChange() {
      this.selectedText = ''
      this.cityName = []
      this.options.map(item => {
        if (item.value === this.selectCity) {
          this.mapLoadCity = item.name
          this.cityName.push(item.name)
        }
      })
      this.mapChart();
    },
    //显示地图
    mapChart() {
      this.map = echarts.init(document.getElementById('mapMain'));
      this.initMenu();
      this.map.on("click", this.mapClick);
    },
    //地图点击事件
    mapClick(param) {
      this.selectedText = `当前选中区域为: ${this.mapLoadCity}--${param.name}`;
    },
    initMenu() {
      this.loadMap(this.mapLoadCity, this.loadData(this.mapLoadCity));
    },
    loadData(mapLoadCity) {
      if (mapLoadCity === '荆州市') {
        return this.JZtestData;
      }
      if (mapLoadCity === '抚州市') {
        return this.FZtestData;
      }
    },
    /**
      * 加载地图
      * @param name
    */
    loadMap(name, mapdataJson) {
      let markPointData = this.mapConfigJson[name]["qxwz"];
      if (!this.mapConfigJson[name].geoJson) {
        return;
      }
      let geoJson = require("../../assets/mapdata" + this.mapConfigJson[name].geoJson);
      echarts.registerMap(name, geoJson);
      let dataColor = () => {
        let colorlist = [];
        for (let i = 0; i < mapdataJson.length; i++) {
          if (mapdataJson[i].value < 1000) {
            colorlist.push("rgb(207,234,254)");
          } else if (mapdataJson[i].value >= 1000 && mapdataJson[i].value < 2000) {
            colorlist.push("rgb(138,184,252)");
          } else if (mapdataJson[i].value >= 2000 && mapdataJson[i].value < 3000) {
            colorlist.push("rgb(101,162,249)");
          } else if (mapdataJson[i].value >= 3000) {
            colorlist.push("rgb(79,132,235)");
          }
        }
        return colorlist;
      }
      let option = {
        geo: [
          {
            geoIndex: 0,
            z: 1,
            type: 'map',
            map: name,
            center: [116.38, 27.56],
            zoom: 1,
            aspectScale: 1.3, //长宽比
            scaleLimit: {
              "min": 1.1,
              "max": 15
            },
            label: { //标签样式设置
              show: true,
              fontSize: 14,
              color: 'rgba(255,255,255)',
            },
            itemStyle: {
              normal: {
                borderColor: "#fff",
                borderWidth: 1,
                areaColor: 'rgb(207,234,254)',
                fontWeightL: 700,
              },
              emphasis: {
                areaColor: 'rgb(243,215,115)',
                borderWidth: 0
              }
            },
            select: {
              itemStyle: {
                areaColor: 'rgb(243,215,115)',
                borderColor: '#fff',
                borderWidth: 3,
                shadowOffsetX: 0,
                shadowOffsetY: 0,
                opacity: 1,
              }
            },
            selectedMode: 'multiple',
          },
          {
            geoIndex: 0,
            map: name,
            z: 0,
            zoom: 1,
            center: [116.348, 27.58],
            aspectScale: 1.3, //长宽比
            scaleLimit: {
              "min": 1.1,
              "max": 15
            },
            label: { //标签样式设置
              show: true,
              fontSize: 14,
              color: 'rgba(150,181,246,0)',
            },
            itemStyle: {
              normal: {
                shadowColor: '#ececec',
                shadowOffsetX: 5,
                shadowOffsetY: 5,
                borderColor: "#fff",
                borderWidth: 1,
                areaColor: 'rgb(187,217,253)',
              },
              emphasis: {
                areaColor: 'rgb(187,217,253)',
                borderWidth: 0
              },
            }
          },
        ],
        visualMap: [{
          min: 0,
          max: 10,
          left: 'left',
          top: 'bottom',
          text: ['高', '低'],
          calculable: true,
          show: false,
          inRange: {
            color: dataColor()
          }
        }],
        color: ['white'],
        series: [
          {
            name: "热力图",
            type: "heatmap",
            coordinateSystem: "geo",
            geoIndex: 0,
            markPoint: { //标记点
              symbol: 'roundRect',
              symbolKeepAspect: true,
              symbolSize: [35, 15], //图形大小
              label: {
                width: 100,
                height: 50,
                normal: {
                  color: '#000',
                  formatter: function (params) {
                    for (let i = 0; i < mapdataJson.length; i++) {
                      if (mapdataJson[i].name == params.name) {
                        return mapdataJson[i].value;
                      }
                    }
                  },
                  show: true,
                },
                emphasis: {
                  show: true,
                }
              },
              itemStyle: {
                color: '#fff',
              },
              data: markPointData
            }
          },
          {
            name: '地市',
            type: 'map',
            geoIndex: 0,
            data: this.getMapColor(geoJson)
          }
        ]
      };
      if (this.mapLoadCity === '荆州市') {
        option.geo[0].center = [112.71, 29.71];
        option.geo[0].zoom = 1.2;
        option.geo[1].center = [112.73, 29.73];
        option.geo[1].zoom = 1.2;
      }
      this.map.setOption(option, true);
    },
    /**
     * 生成地图颜色
     * @param geoJson
     * @returns {Array}
     */
    getMapColor(geoJson) {
      let list = [];
      for (let i in geoJson.features) {
        let feature = geoJson.features[i];
        let name = feature.properties.name;
        let json = {};
        json.name = name;
        json.value = i % 11;
        if (this.cityName.length == 2) {
          if (this.cityName[1] == name) {
            json.selected = true;
          }
        }
        list.push(json);
      }
      return list;
    },
  }
}
  • CSS:

组件内样式

.mapMain {
  width: 1000px;
  height: 750px;
}

全局样式(在 assets 下新建 CSS 目录,下新增 common.css 文件)

* {
    margin: 0;
    padding: 0;
}

html,
body {
    font-size: 24px;
    font-family: '楷体' !important;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
}

.home {
    width: 1000px;
    height: 800px;
    border: 1px solid black;
    padding: 10px;
    margin: 0 auto;
}

.header {
    width: 100%;
    height: 50px;
    text-align: center;
    line-height: 50px;
    color: white;
    background: black;
}

.main {
    width: 100%;
    height: 750px;
    background: lavender;
    position: relative;
    z-index: 1;
}

.select {
    position: absolute;
    top: 20px;
    left: 20px;
    width: 80px;
    height: 30px;
    border: 1px solid rgba(0, 0, 0, .4);
    cursor: pointer;
    text-align: center;
    line-height: 30px;
    z-index: 999;
}

.selectedText {
    border-bottom: 2px solid lightblue;
    position: absolute;
    top: 20px;
    right: 20px;
    font-size: 15px;
    z-index: 999;
}

模拟测试数据

使用 vuex 模拟后端请求到的地图数据,存放在 store 下的 index.js 文件中的 state 内 。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        JZtestData: [{
                name: "洪湖市",
                qxdm: "421083",
                value: 654
            },
            {
                name: "江陵县",
                qxdm: "421024",
                value: 13
            },
            {
                name: "荆州区",
                qxdm: "421003",
                value: 4222
            },
            {
                name: "沙市区",
                qxdm: "421002",
                value: 1854
            },
            {
                name: "松滋市",
                qxdm: "421087",
                value: 1023
            },
            {
                name: "公安县",
                qxdm: "421022",
                value: 10
            },
            {
                name: "监利县",
                qxdm: "421023",
                value: 2183
            },
            {
                name: "石首市",
                qxdm: "421081",
                value: 12
            }
        ],
        FZtestData: [{
                name: "东乡区",
                qxdm: "361029",
                value: 654
            },
            {
                name: "临川区",
                qxdm: "361002",
                value: 13
            },
            {
                name: "金溪县",
                qxdm: "361027",
                value: 4222
            },
            {
                name: "崇仁县",
                qxdm: "361024",
                value: 1854
            },
            {
                name: "宜黄县",
                qxdm: "361026",
                value: 1023
            },
            {
                name: "南城县",
                qxdm: "361021",
                value: 10
            },
            {
                name: "资溪县",
                qxdm: "361028",
                value: 2183
            },
            {
                name: "乐安县",
                qxdm: "361025",
                value: 12
            },
            {
                name: "南丰县",
                qxdm: "361023",
                value: 10
            },
            {
                name: "黎川县",
                qxdm: "361022",
                value: 2183
            },
            {
                name: "广昌县",
                qxdm: "361030",
                value: 12
            }
        ],
         options: [{
             name: '荆州市',
             value: '421000'
         }, {
             name: '抚州市',
             value: '361000'
         }]
    },
    mutations: {},
    actions: {},
    modules: {}
})

中国地图下钻省市区县


获取中国【省市区县】json 数据 

安装 province-city-china 依赖。 

npm i province-city-china -S

数据项解析 

请求已安装的 province-city-china 依赖包,获取各项数据。

参考链接https://juejin.cn/post/6844903527844675591

const { data, province, city, area, town } = require('province-city-china/data');
// data - 总数据(省/地/县/乡)
// province - 省级(省/直辖市/特别行政区)
// city - 地级(城市)
// area - 县级(区县)
// town - 乡级(乡镇/街)

组件案例

  • HTML
<template>
  <div>
    <div id="tool">
      <span @click="goBackChina">{{firstTitle}}</span>
      <span @click="goBackProvince">{{currentProvince.name}}</span>
      <span @click="goBackCity">{{currentCity.name}}</span>
    </div>
    <div id="chinaMap"></div>
  </div>
</template>
  • JS 
import * as echarts from 'echarts';
const { province, city } = require('province-city-china/data');

export default {
  name: 'ChinaMain',
  data() {
    return {
      firstTitle: '中国',
      myChart: '',
      currentClick: '',
      currentProvince: {},
      currentCity: {},
      cityState: false,
      provinceState: false
    }
  },
  mounted() {
    this.initEcharts("china", "中国");
  },
  methods: {
    goBackChina() {
      this.initEcharts("china", "中国");
      this.currentProvince.name = '';
      this.currentCity.name = '';
    },
    goBackProvince() {
      this.initEcharts(this.currentProvince.province, this.currentProvince.name, "1");
      this.currentCity.name = '';
    },
    goBackCity() {
      this.initEcharts(this.currentCity.code, this.currentCity.name);
    },
    initEcharts(pName, Chinese_, state = "0") {
      this.myChart = echarts.init(document.getElementById('chinaMap'));
      let tmpSeriesData = [];
      if (pName === "china") {
        let geoJson = require('../../assets/mapdata/china.json');
        echarts.registerMap(pName, geoJson);
      } else {
        if (this.currentClick === 'province' || state === "1") {
          let geoJson = require(`../../assets/mapdata/geometryProvince/${pName}.json`);
          echarts.registerMap(pName, geoJson);
        } else {
          let geoJson = require(`../../assets/mapdata/geometryCouties/${pName}.json`);
          echarts.registerMap(pName, geoJson);
        }
      }
      let option = {
        series: [
          {
            name: Chinese_ || pName,
            type: 'map',
            mapType: pName,
            roam: false,//是否开启鼠标缩放和平移漫游
            itemStyle: {//地图区域的多边形 图形样式
              normal: {//是图形在默认状态下的样式
                label: {
                  show: true,//是否显示标签
                  textStyle: {
                    color: "#303133",
                    fontSize: '10px'
                  }
                }
              },
              emphasis: {//是图形在高亮状态下的样式,比如在鼠标悬浮或者图例联动高亮时
                label: {
                  show: true,
                  textStyle: {
                    fontSize: '14px'
                  }
                }
              }
            },
            data: tmpSeriesData,//后端数据
            top: "10%"//组件距离容器的距离
          }
        ]
      };
      this.myChart.setOption(option, true);
      this.myChart.off("click");
      if (pName === "china") { // 全国时,添加click 进入省级
        this.currentClick = 'province'
        this.myChart.on('click', this.mapClick);
      } else {
        this.currentClick = 'city'
        this.myChart.on('click', this.mapClick);
      }
    },
    //地图点击事件
    mapClick(param) {
      this.provinceState = false;
      this.cityState = false;
      if (this.currentClick === 'province') {
        //遍历取到provincesText 中的下标  去拿到对应的省js
        for (var i = 0; i < province.length; i++) {
          if (param.name === province[i].name) {
            this.provinceState = true;
            this.currentProvince = { ...province[i] };
            this.currentProvince.name = ` -->${this.currentProvince.name} `;
            //显示对应省份的方法
            this.showProvince(province[i].province, province[i].name);
            break;
          }
        }
        !this.provinceState ? alert('暂不支持该区域地图展示!') : '';
      } else {
        for (var l = 0; l < city.length; l++) {
          if (param.name === city[l].name) {
            this.cityState = true;
            this.currentCity = { ...city[l] };
            this.currentCity.name = ` -->${this.currentCity.name} `;
            //显示对应城市的方法
            this.showProvince(city[l].code, city[l].name);
            break;
          }
        }
        !this.cityState ? alert('暂不支持该区域地图展示!') : '';
      }
    },
    showProvince(pName, Chinese_) {
      this.initEcharts(pName, Chinese_);
    }
  }
}
  • CSS 
#tool {
  height: 30px;
  line-height: 30px;
  color: deepskyblue;
  cursor: pointer;
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 10000;
  font-size: 18px;
  text-align: left;
}
#chinaMap {
  width: 1000px;
  height: 750px;
}

完整示例,注意事项 


完整示例

完整示例链接https://gitee.com/wu241617/echarts-map

注意事项 

【注意】: 在完整示例中,码云下拉代码到本地后,npm install 安装依赖,npm run serve 启动项目,默认显示 /home 路由页面,中国下钻省市区县页面通过 /cm 路由访问。依赖于 mapdata 资源包和 province-city-china  依赖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值