echarts实现一个显示所有城市的中国地图

1,168 阅读6分钟

说在前面

显示省份的中国地图大家应该都实现过了吧?那么显示全国所有城市的中国地图大家实现过吗?最近刚好自己在实现一个小功能需要显示全国所有城市的中国地图,在这里分享一下怎么快速实现一个。

效果展示

体验地址:jyeontu.xyz/JDemo/#/Chi…

GeoJSON

GeoJSON 是一种用于编码各种地理数据结构的格式,在 ECharts 地图中常被用来定义地理区域的形状和属性。

实现过echarts地图的同学们应该都清楚,我们需要提供一个json文件来注册对应的地图,这个json文件的格式如下:

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "id": "province",
            "properties": {
                "name": "province",
                "cp": [
                    longitude,
                    latitude
                ],
                "childNum": xxx
            },
            "geometry": {
                "type": "Polygon",
                "coordinates": []
            }
        }
        …………
    ]
}

顶层对象属性

{
    "type": "FeatureCollection",
    "features": [...]
}
  • type:指定 GeoJSON 对象的类型。FeatureCollection 表示这是一个包含多个 Feature(地理要素)的集合。在地图数据中,一个 FeatureCollection 可以包含多个地理区域(如省份、城市等)的信息。
  • features:是一个数组,包含了多个 Feature 对象,每个 Feature 对象代表一个具体的地理要素,比如一个省份或一个城市。

Feature 对象属性

{
    "type": "Feature",
    "id": "xin_jiang",
    "properties": {
        "name": "新疆",
        "cp": [84.9023, 41.748],
        "childNum": 18
    },
    "geometry": {
        "type": "Polygon",
        "coordinates": []
    }
}

1. type

指定该对象的类型为 Feature,表示这是一个具体的地理要素。

2. id

为该地理要素分配的唯一标识符,这里是 "xin_jiang",通常用于在代码中引用该地理要素,方便进行数据关联和操作。

3. properties

一个包含该地理要素相关属性的对象,可根据实际需求自定义属性。

  • name:地理要素的名称,这里是 "新疆",用于在地图上显示或进行数据匹配等操作。
  • cp:通常表示该地理要素的中心点坐标,是一个包含经度和纬度的数组 [84.9023, 41.748]。这个中心点坐标可用于地图定位、标注等功能。
  • childNum:自定义属性,表示该地理要素包含的子区域数量,这里是 18,具体含义取决于数据的使用场景,可能表示该省份包含的城市数量等。

4. geometry

定义该地理要素的几何形状,包含以下属性:

  • type:指定几何形状的类型,这里是 "Polygon",表示这是一个多边形,常用于表示地理区域的边界。
  • coordinates:是一个数组,用于存储多边形的顶点坐标。在这个示例中,数组为空,实际使用时应包含一系列经纬度坐标对,按顺序连接这些坐标点可形成多边形的边界。例如:
"coordinates": [
    [
        [longitude1, latitude1],
        [longitude2, latitude2],
        [longitude3, latitude3],
        ...
    ]
]

重组地理区域

通过前面对GeoJSON的了解后,我们可以知道每个省份(城市)的边界其实就是通过json中的coordinates数组来绘制的,那么只要我们修改一下coordinates数组,将中国所有城市的边界都绘制出来就可以了。

所有城市的GeoJSON

首先我们需要先获取到中国各个省份的GeoJSON文件,这里我已经整理好上传到Gitee上了,有需要的同学也可以自取

Gitee地址:gitee.com/zheng_yongt…

重组GeoJSON

现在我们已经有了中国所有省份城市的地图数据,那么只需要写个脚本将各个省份城市地图数据重新组合一下即可。

1.引入模块和初始化数据

const fs = require("fs");

const chinaJson = {
  type: "FeatureCollection",
  features: [],
};
  • fs 是 Node.js 的内置文件系统模块,用于文件的读取、写入等操作。
  • chinaJson 是一个空的 GeoJSON 格式对象,后续会将各省份的地理数据添加到 features 数组中。

2.特殊省份处理

港澳台和直辖市我们都直接显示整个省级区域就好:

const china = require("./china.json");
const keepProvinces = ["台湾", "香港", "澳门", "北京", "上海", "重庆", "天津"];
china.features.forEach((feature) => {
  if (keepProvinces.includes(feature.properties.name)) {
    feature.properties.province = feature.properties.name;
    chinaJson.features.push(feature);
  }
});
  • china:通过 require 引入 china.json 文件,包含全国省份地理数据的基础信息。
  • keepProvinces:定义了需要保留完整区域的省份名称数组。
  • 遍历 china 中的 features,如果省份名称在 keepProvinces 数组中,则为该地理要素的 properties 添加 province 属性,并将其添加到 chinaJson.features 中。

3.构建省份名称映射表

const list = [
  { ename: "nanhaizhudao", name: "南海诸岛" },
  { ename: "beijing", name: "北京" },
  // 其他省份信息...
];
const provinceMap = {};
list.forEach((item) => {
  provinceMap[item.ename] = item.name;
});
  • list:一个包含省份英文名称和中文名称对应关系的数组。
  • provinceMap:通过遍历 list 构建的映射表,键为省份英文名称,值为省份中文名称。

4.处理剩余省份数据

const provinces = fs.readdirSync("./省份数据/json(省份)");
provinces.forEach((province) => {
  if (
    [
      "xianggang.json",
      "aomen.json",
      "taiwan.json",
      "shanghai.json",
      "beijing.json",
      "chongqing.json",
      "tianjin.json",
    ].includes(province)
  )
    return;
  const provinceJson = require(`./省份数据/json(省份)/${province}`);
  const provinceFeatures = provinceJson.features;
  provinceFeatures.forEach((feature) => {
    feature.properties.province = provinceMap[province.replace(".json", "")];
    chinaJson.features.push(feature);
  });
});
  • 遍历 provinces 数组,跳过之前已经处理过的省份文件。
  • 对于每个省份文件,引入该文件并获取其 features
  • 为每个地理要素的 properties 添加 province 属性,属性值通过 provinceMap 映射得到。
  • 将处理后的地理要素添加到 chinaJson.features 中。

5. 生成chinaCity.json文件

fs.writeFileSync("./chinaCity.json", JSON.stringify(chinaJson));

将整合后的 chinaJson 对象转换为 JSON 字符串,并同步写入 chinaCity.json 文件。

6.完整代码

const fs = require("fs");

const chinaJson = {
  type: "FeatureCollection",
  features: [],
};

const provinces = fs.readdirSync("./省份数据/json(省份)");
const china = require("./china.json");
const keepProvinces = ["台湾", "香港", "澳门", "北京", "上海", "重庆", "天津"];
china.features.forEach((feature) => {
  if (keepProvinces.includes(feature.properties.name)) {
    feature.properties.province = feature.properties.name;
    chinaJson.features.push(feature);
  }
});
const list = [
  { ename: "nanhaizhudao", name: "南海诸岛" },
  { ename: "beijing", name: "北京" },
  { ename: "tianjin", name: "天津" },
  { ename: "shanghai", name: "上海" },
  { ename: "chongqing", name: "重庆" },
  { ename: "hebei", name: "河北" },
  { ename: "henan", name: "河南" },
  { ename: "yunnan", name: "云南" },
  { ename: "liaoning", name: "辽宁" },
  { ename: "heilongjiang", name: "黑龙江" },
  { ename: "hunan", name: "湖南" },
  { ename: "anhui", name: "安徽" },
  { ename: "shandong", name: "山东" },
  { ename: "xinjiang", name: "新疆" },
  { ename: "jiangsu", name: "江苏" },
  { ename: "zhejiang", name: "浙江" },
  { ename: "jiangxi", name: "江西" },
  { ename: "hubei", name: "湖北" },
  { ename: "guangxi", name: "广西" },
  { ename: "gansu", name: "甘肃" },
  { ename: "shanxi", name: "山西" },
  { ename: "neimenggu", name: "内蒙古" },
  { ename: "shanxi1", name: "陕西" },
  { ename: "jilin", name: "吉林" },
  { ename: "fujian", name: "福建" },
  { ename: "guizhou", name: "贵州" },
  { ename: "guangdong", name: "广东" },
  { ename: "qinghai", name: "青海" },
  { ename: "xizang", name: "西藏" },
  { ename: "sichuan", name: "四川" },
  { ename: "ningxia", name: "宁夏" },
  { ename: "hainan", name: "海南" },
  { ename: "taiwan", name: "台湾" },
  { ename: "xianggang", name: "香港" },
  { ename: "aomen", name: "澳门" },
];
const provinceMap = {};
list.forEach((item) => {
  provinceMap[item.ename] = item.name;
});
provinces.forEach((province) => {
  if (
    [
      "xianggang.json",
      "aomen.json",
      "taiwan.json",
      "shanghai.json",
      "beijing.json",
      "chongqing.json",
      "tianjin.json",
    ].includes(province)
  )
    return;
  const provinceJson = require(`./省份数据/json(省份)/${province}`);
  const provinceFeatures = provinceJson.features;
  provinceFeatures.forEach((feature) => {
    feature.properties.province = provinceMap[province.replace(".json", "")];
    chinaJson.features.push(feature);
  });
});
fs.writeFileSync("./chinaCity.json", JSON.stringify(chinaJson));

echarts地图配置

地图容器

创建一个div作为展示地图的容器

<div id="ChinaCityMapContent"></div>

地图文件注册

将前面生成的json文件导入,并使用echarts.registerMap进行注册。

const chinaJson = require("../../utils/chinaCity.json");

this.$echarts.registerMap("china", chinaJson);

地图配置

initEchart() {
  const ChinaCityMapContent = document.getElementById(
    "ChinaCityMapContent"
  );
  ChinaCityMapContent.style.width = window.innerWidth - 10 + "px";
  const myChart = this.$echarts.init(ChinaCityMapContent);
  this.$echarts.registerMap("china", chinaJson);
  const option = {
    tooltip: {
      show: false
    },
    visualMap: {
      show: false //图注
    },
    geo: {
      map: "china", //引入地图数据
      roam: true, //开启缩放和平移
      zoom: 3, //视角缩放比例
      label: {
        normal: {
          show: true,
          fontSize: "10",
          color: "rgba(0,0,0,0.7)"
        }
      },
      itemStyle: {
        normal: {
          borderColor: "rgba(0, 0, 0, 0.2)"
        },
        emphasis: {
          //高亮的显示设置
          areaColor: "skyblue", //鼠标选择区域颜色
          shadowOffsetX: 0,
          shadowOffsetY: 0,
          shadowBlur: 20,
          borderWidth: 0,
          shadowColor: "rgba(0, 0, 0, 0.5)"
        }
      }
    },
    // 鼠标悬浮提示框
    series: [
      {
        name: "城市",
        type: "map",
        geoIndex: 0,
        data: this.dataList
      }
    ]
  };
  myChart.setOption(option);
}
  • tooltip:设置鼠标悬浮提示框不显示。
  • visualMap:设置图注不显示。
  • geo:地图的地理坐标系配置。
  • map:指定使用名为 "china" 的地图。
  • roam:开启地图的缩放和平移功能。
  • zoom:设置地图的初始缩放比例为 3。
  • label:设置地图上标签的样式,正常状态下显示,字体大小为 10,颜色为半透明黑色。
  • itemStyle:设置地图区域的样式,正常状态下边框颜色为半透明黑色,鼠标悬停时区域颜色变为天蓝色,添加阴影效果。
  • series:地图系列配置,指定类型为 map,使用第一个地理坐标系(geoIndex: 0)。

源码

组件源码已开源到gitee,有兴趣的也可以到这里看看:gitee.com/zheng_yongt…

  • 🌟觉得有帮助的可以点个star~
  • 🖊有什么问题或错误可以指出,欢迎pr~
  • 📬有什么想要实现的组件或想法可以联系我~

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

公众号发送 加群 可以加入群聊,一起来学习(摸鱼)吧~

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。