如何使用ECharts绘制中国地图(结合CDN和阿里地图免下载JSON版)

前端 潘老师 2周前 (04-09) 24 ℃ (0) 扫码查看

使用ECharts绘制中国地图是常见需求,今天就给大家分享一种利用CDN和阿里地图资源来实现的方法,而且无需下载JSON文件,方便又高效。

一、基础设置:防止403错误

在项目的index.html文件里,添加下面这行代码,它的作用是防止出现403错误:

<meta name="referrer" content="no-referrer" />

这行代码设置了页面的引用策略,避免在请求资源时因引用问题导致403错误,为后续顺利加载地图资源做好准备。

二、数据与图表初始化

接下来,要对数据赋值,同时初始化图表和配置项option。这里以初始化全国地图配置为例:

// 初始化绘制全国地图配置
option: {
  backgroundColor: "transparent", // 设置背景色透明
  // 必须设置
  tooltip: {
    show: false
  },
  // 地图阴影配置
}

在这段代码中,设置了地图的背景为透明,并且暂时隐藏了提示框tooltip。大家可以根据实际需求,对这些初始配置进行调整。

三、挂载阶段:初始化地图相关操作

mounted钩子函数中,主要进行地图初始化、获取地图以及获取图表的操作:

mounted() {
  this.initMap();
  this.getMap();
  this.myChart = window.echarts.init(document.getElementById("centerMap"));
}

initMap()getMap()是自定义的方法,分别用于初始化地图数据和获取地图资源。window.echarts.init(document.getElementById("centerMap"))则是使用ECharts的init方法,通过传入对应的DOM元素ID,来初始化一个ECharts图表实例。

四、初始化地图:获取数据并绘制

initMap函数主要负责从阿里地图获取数据,注册地图,绘制地图并绑定点击事件:

async initMap() {
  document.getElementById("back").style.display = "none";
  await axios
  .get(`https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json`)
  .then((res) => {
      // 获取所有省份
      let shengAll = this.getChildMap(res.data);
      // 注册大地图
      window.echarts.registerMap("china", res.data);
      // 绘制地图
      this.renderMap("china", shengAll);
      // 绑定点击地图区域事件
      this.myChart.on("click", this.clickMap);
    });
}

这里通过axios.get从阿里云的地图数据接口获取中国地图的JSON数据。拿到数据后,先调用getChildMap方法处理数据,获取所有省份信息。接着使用window.echarts.registerMap注册地图,renderMap方法绘制地图,最后绑定点击事件clickMap,方便后续实现点击地图的交互功能。

五、点击地图:切换地图层级

点击地图后,要根据点击的区域判断地图类型,并显示相应层级的地图:

clickMap(params) {
  document.getElementById("back").style.display = "block";
  const name = params.name;
  const adcode = this.getAdcodeFromGeoJSON(name);
  const geoLevel = this.getAdcodeFromGeoLevel(name);
  if (geoLevel == "province" || geoLevel == "city") {
    if (name == "台湾省") {
      this.$message.warning("已经是最后一层地图了");
    } else {
      axios
      .get(`https://geo.datav.aliyun.com/areas_v3/bound/${adcode}_full.json`)
      .then((res) => {
          // 注册省级地图
          window.echarts.registerMap(params.name, res.data);
          // 获取当前省下所有市
          let shiAll = this.getChildMap(res.data);
          this.renderMap(params.name, shiAll);
        });
    }
  } else {
    this.$message.warning("没有更小的地图了");
    // this.renderMap("china");
  }
}

这段代码中,先获取点击区域的名称name,再通过getAdcodeFromGeoJSONgetAdcodeFromGeoLevel方法获取对应的行政区划代码adcode和地图层级geoLevel。如果点击的是省份或城市,且不是台湾省,就获取该区域的详细地图数据,注册地图并绘制;如果点击的区域没有更小层级的地图,则给出提示。

六、辅助方法:获取信息

(一)获取adcode和地图类型

getAdcodeFromGeoJSON方法用于从GeoJSON数据中获取adcode

getAdcodeFromGeoJSON(name) {
  const geoJSON = window.echarts.getMap(this.option.geo.map).geoJSON;
  for (let feature of geoJSON.features) {
    if (feature.properties.name === name) {
      return feature.properties.adcode;
    }
  }
  return null;
}

这个方法通过遍历当前地图的GeoJSON数据,找到与点击名称匹配的区域,返回其adcode,找不到则返回null

getAdcodeFromGeoLevel方法用于获取地图类型:

getAdcodeFromGeoLevel(name) {
  const geoLevel = window.echarts.getMap(this.option.geo.map).geoJSON;
  for (let feature of geoLevel.features) {
    if (feature.properties.name === name) {
      return feature.properties.level;
    }
  }
  return null;
}

该方法与上面类似,只不过返回的是匹配区域的地图层级信息。

(二)获取下级所有地名

getChildMap方法用于获取下级所有地名:

getChildMap(data) {
  let childMapAll = [];
  // value为鼠标悬停地名显示的数据
  for (var i = 0; i < data.features.length; i++) {
    childMapAll.push({
      name: data.features[i].properties.name,
      value: 0
    });
  }
  return childMapAll;
}

这个方法遍历传入的地图数据,将每个区域的名称和初始值0组成对象,添加到数组中,最后返回包含所有下级地名的数组。

七、渲染地图:配置与更新

renderMap方法用于修改ECharts配置并重新渲染地图,实现地图的缩放、拖动等功能:

renderMap(map, data) {
  // 标题
  this.option.geo = {
    map: map,
    // 这里必须定义,不然后面series里面不生效
    tooltip: {
      show: false
    },
    label: {
      show: false
    },
    zoom: 1.03,
    silent: true, // 不响应鼠标时间
    show: true,
    roam: false, // 地图缩放和平移
    aspectScale: 0.75,
    layoutSize: "108%",
    itemStyle: {
      normal: {
        borderColor: "rgba(147, 235, 248, 1)",
        borderWidth: 0.5,
        color: {
          type: "linear-gradient",
          x: 0,
          y: 1500,
          x2: 2500,
          y2: 0,
          colorStops: [
            {
              offset: 0,
              color: "#009DA1" // 0% 处的颜色
            },
            {
              offset: 1,
              color: "#005B9E" // 50% 处的颜色
            }
          ],
          global: true // 缺省为 false
        },
        opacity: 0.5
      },
      emphasis: {
        areaColor: "#2a333d"
      }
    },
    // 地图区域的多边形 图形样式 阴影效果
    // z值小的图形会被z值大的图形覆盖
    top: "18%",
    left: "center",
    // 去除南海诸岛阴影 series map里面没有此属性
    regions: [
      {
        name: "南海诸岛",
        selected: false,
        emphasis: {
          disabled: true
        },
        itemStyle: {
          areaColor: "#00000000",
          borderColor: "#00000000"
        }
      }
    ],
    z: 1
  };
  this.option.series = [
    // 地图配置
    {
      type: "map",
      map: map,
      zoom: 1,
      tooltip: {
        show: false
      },
      label: {
        show: true, // 显示省份名称
        color: "#04CFF5",
        align: "center"
      },
      top: "18%",
      left: "center",
      aspectScale: 0.75,
      layoutSize: "108%",
      roam: false, // 地图缩放和平移
      itemStyle: {
        borderColor: "#0FA3F0", // 省分界线颜色  阴影效果的
        borderWidth: 1,
        areaColor: "#065CAE",
        opacity: 1
      },
      // 去除选中状态
      select: {
        disabled: true
      },
      emphasis: {
        // 聚焦后颜色
        disabled: false, // 开启高亮
        label: {
          align: "center",
          color: "#04CFF5"
        },
        itemStyle: {
          color: "#ffffff",
          areaColor: "#0a8bd8" // 阴影效果 鼠标移动上去的颜色
        }
      },
      z: 2
    },
    // 点
    {
      name: "companyPoint",
      type: "effectScatter",
      coordinateSystem: "geo",
      showEffectOn: "render",
      // zlevel: 2, // zlevel用于 Canvas 分层 相同的绘制在同一个canvas上
      rippleEffect: {
        number: 3, // 波纹数量
        period: 4, // 动画周期 数值越大,波动越慢
        scale: 3.5, // 动画中波纹的最大缩放比例
        brushType: "stroke" // 波纹的绘制方式 stroke fill
      },
      label: {
        show: false,
        position: "right",
        formatter: "{b}",
        color: "#97e9e1",
        fontSize: 14
      },
      symbol: "circle",
      symbolSize: 10,
      tooltip: {
        show: true,
        padding: 0,
        borderWidth: 0,
        backgroundColor: "rgba(17, 132, 87,0.8)",
        textStyle: {
          fontSize: 14,
          color: "#fff"
        },
        formatter: function (params) {
          // console.log(params, 222);
          var data = params.data;
          return (
            "&nbsp;&nbsp;&nbsp;&nbsp;" +
            "所属用户:" +
            data.name +
            "<br>" +
            "&nbsp;&nbsp;&nbsp;&nbsp;" +
            "设备编号:" +
            data.deviceId +
            "<br>" +
            "&nbsp;&nbsp;&nbsp;&nbsp;" +
            "位置描述:" +
            data.location +
            "&nbsp;&nbsp;&nbsp;&nbsp;" +
            "<br>" +
            "&nbsp;&nbsp;&nbsp;&nbsp;" +
            "数据时间:" +
            data.dataTime
          );
        }
      },
      z: 4
    }
  ];
  // 重新渲染echarts
  if (map == "china") {
    this.option.geo.layoutCenter = ["50%", "65%"];
    this.option.series[0].layoutCenter = ["50%", "65%"];
    this.option.geo.roam = false;
    this.option.series[0].roam = false; // 地图缩放和平移
  } else {
    this.option.geo.layoutCenter = ["50%", "50%"];
    this.option.series[0].layoutCenter = ["50%", "50%"];
    this.option.geo.roam = true;
    this.option.series[0].roam = true; // 地图缩放和平移
    this.myChart.on("georoam", (params) => {
      var option = this.myChart.getOption(); //获得option对象
      if (params.zoom != null && params.zoom != undefined) {
        //捕捉到缩放时
        option.geo[0].zoom = option.series[0].zoom; //下层geo的缩放等级跟着上层的geo一起改变
        option.geo[0].center = option.series[0].center; //下层的geo的中心位置随着上层geo一起改变
        this.myChart.getZr().on("mousewheel", (event) => {
          var zoom = option.geo[0].zoom;
          var zooms = option.series[0].zoom;
          var newZoom = event.wheelDelta > 0? zoom * 2 : zoom / 2;
          var newZooms = event.wheelDelta > 0? zooms * 2 : zooms / 2;
          newZoom = Math.max(1, Math.min(200, newZoom)); // 限制缩放级别
          newZooms = Math.max(1, Math.min(200, newZooms)); // 限制缩放级别
          this.myChart.setOption(
            {
              geo: {
                zoom: newZoom
              },
              series: [
                {
                  zoom: newZooms
                }
              ]
            },
            { lazyUpdate: true }// 是否延迟更新  
          );
        });
      } else {
        //捕捉到拖曳时
        option.geo[0].center = option.series[0].center; //下层的geo的中心位置随着上层geo一起改变
        this.myChart.setOption(option, { lazyUpdate: true }); //设置option// 是否延迟更新  
      }
    });
  }
  this.option.series[1].data = this.provinceData; // 假设数据加载到data变量中
  // // 更新图表数据
  this.myChart.setOption(this.option, true); // 第二个参数为true表示不合并之前的option,而是完全替换
  //随着屏幕大小调节图表
  window.addEventListener("resize", () => {
    this.myChart.resize();
  });
}

这个方法配置了地图的各种属性,包括地图样式、缩放、拖动、标记点等。根据传入的地图名称,设置不同的布局和交互方式。最后更新图表数据,并添加监听窗口大小变化的事件,使图表能自适应屏幕变化。

通过以上步骤,我们就利用CDN和阿里地图资源,完成了ECharts中国地图的开发,并且实现了地图层级切换、缩放、拖动等功能。大家可以根据实际项目需求,对代码进行进一步优化和扩展。希望这篇文章能帮助到正在做相关开发的朋友们。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/front/17065.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】