说在前面
显示省份的中国地图大家应该都实现过了吧?那么显示全国所有城市的中国地图大家实现过吗?最近刚好自己在实现一个小功能需要显示全国所有城市的中国地图,在这里分享一下怎么快速实现一个。
效果展示
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,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。