哈喽,各位高贵的倔友们你们好呀(✪ω✪),今天小编给各位分享一篇关于高德地图内容的文章,如果各位倔友觉得还不错,期望点个赞呗,那我们话不多说,直接进入正题。
写在开头
申请Web端开发者Key和安全密钥
要使用高德地图,我们必须先去高德地图官网注册成为开发者,并创建应用申请得到一个开发者 Key
与安全密钥。
注册/登录 -> 右上角头像 -> 应用管理 -> 点击”创建新应用”按钮 -> 添加 Key
。
上面我们简单给个过程路径就不再多说啦,很简单的,更加详细的过程可以看看这里。传送门
安装
然后我们需要安装高德地图的依赖包:
npm install @amap/amap-jsapi-loader --save
初始化地图
装好依赖后,就能初始化地图了。
新建 AreaMap.vue
文件:
<template>
<div id="container" />
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
export default {
data() {
return {
// map:null, // 此处不声明 map 对象,可以直接使用 this.map 赋值或者采用非响应式的普通对象来存储。
}
},
async mounted() {
await this.initMap();
},
methods: {
/** @name 初始化地图 **/
initMap() {
return new Promise(resolve => {
window._AMapSecurityConfig = {
securityJsCode: '你的安全密钥', // 自2021年12月02日升级后, key与安全密钥必须一起使用, 否则可能会出现一些API无法使用,如 DistrictSearch
}
AMapLoader.load({
key: '你的Key', // 首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
}).then((AMap)=>{
this.map = new AMap.Map('container', {
center: [110.17293, 35.20173],
zoom: 4.8,
});
this.map.on('complete', () => {
resolve();
});
}).catch(e=>{
console.log(e);
})
})
}
}
}
</script>
<style scoped>
#container {
width: 740px;
height: 500px;
}
</style>
这里小编使用的是 Vue
,对于其他技术栈初始化地图,可以看看这里传送门。
数据准备
这里小编先准备了一些测试数据,下面会以这种数据结构来编写逻辑,如果你真实的数据结构与此不同,可以自行再转换一下或者适当调整一下代码逻辑。
创建 data.js
文件:
const data = [
{
"province": "北京市",
"city": "北京城区",
"area": "西城区",
"append": "北京市北京城区西城区3",
"lng": "116.365868",
"lat": "39.912289",
},
{
"province": "上海市",
"city": "上海城区",
"area": "静安区",
"append": "上海市上海城区静安区5",
"lng": "121.459384",
"lat": "31.247105",
},
{
"province": "广东省",
"city": "广州市",
"area": "黄埔区",
"append": "广东省广州市黄埔区4",
"lng": "113.459749",
"lat": "23.106402",
},
{
"province": "四川省",
"city": "成都市",
"area": "青羊区",
"append": "四川省成都市青羊区6",
"lng": "104.062499",
"lat": "30.674406",
},
{
"province": "河北省",
"city": "石家庄市",
"area": "桥西区",
"append": "河北省石家庄市桥西区2",
"lng": "114.461154",
"lat": "38.004043",
},
{
"province": "重庆市",
"city": "重庆城区",
"area": "涪陵区",
"append": "重庆市重庆城区涪陵区1",
"lng": "107.389298",
"lat": "29.703113",
},
];
export default data;
需要注意,上面小编虽然只列举了几条数据,但像这种以后可能会增大的数据量,一定不要直接挂载到
Vue
身上,要不消耗的依赖收集行为会特别影响性能!!!
不要问我为什么知道的(•́へ•́╬)。
地图板块颜色标注
完成准备工作后,我们就要进入本章的主题对“地图区域板块”进行自定义颜色标注,该功能主要使用到高德地图的 AMap.DistrictLayer
图层对象。
该对象使用方式很简单,我们主要关注它的 adcode
参数,它表示区域板块的行政编码,下面小编写了一个简单案例,请观看:
adcode
参数官方文档写得是String
类型,但实际还支持Array
类型。
<script>
export default {
...
async mounted() {
await this.initMap();
// 初始完地图后,开始绘制
this.drawAreaMap();
},
methods: {
...,
/** @name 绘制区域地图 **/
drawAreaMap() {
const instance = new window.AMap.DistrictLayer.Province({
adcode: ["310000", "110000", "510000", "440000", "130000", "500000", "500000"],
depth: 0,
styles: {
'fill': 'red',
},
});
instance.setMap(this.map);
},
}
}
</script>
具体效果:
是不是很简单(✪ω✪),然后你以为这就完了?当然还没,接下来我们需要解决两个问题。
- 开头我们提前准备的数据里面是没有行政编码的,这个行政编码只能从高德那边获取回来。
- 我们需要实现对不同区域板块标注不同的颜色。
获取行政编码
行政编码的获取,高德提供了一个 AMap.DistrictSearch 对象供我们查询,它属于额外的插件服务,需要在地图初始化的时候进行配置。
具体配置如下:
/** @name 初始化地图 **/
initMap() {
return new Promise(resolve => {
...
AMapLoader.load({
key: '你的Key',
version: '2.0',
plugins: [ // 配置行政区查询服务
'AMap.DistrictSearch'
],
})
...
})
}
后续如果使用到其他一些额外服务都是在 plugins
这里进行配置。
接下来我们就把数据的地址信息转换成具体的行政编码:
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
import data from './data.js';
export default {
...
async mounted() {
await this.initMap();
// 初始完地图后,开始绘制
this.drawAreaMap();
},
methods: {
...,
/** @name 绘制区域地图 **/
drawAreaMap() {
const allAdCode = await this.getAllAdCode();
console.log('allAdCode', allAdCode);
// 获取数据对应的"省级"行政编码
const adcode = [];
data.forEach(address => {
allAdCode.districtList.forEach(province => {
if(address.province === province.name) {
adcode.push(province.adcode)
}
})
})
const instance = new window.AMap.DistrictLayer.Province({
adcode,
depth: 0,
styles: {
'fill': 'red',
},
});
instance.setMap(this.map);
},
/** @name 获取所有区域板块的行政编码 **/
getAllAdCode() {
return new Promise(resolve => {
const searchInstance = new window.AMap.DistrictSearch({
subdistrict: 3, // 获取的下级行政区"级数"
showbiz: false, // 是否显示商圈, 这里用不上直接false
});
searchInstance.search('中国', (status, result) => {
if (status === 'complete') {
resolve(result.districtList[0]);
}
});
});
}
}
}
</script>
subdistrict
参数有四个值:0、1、2、3
。默认值为 1
, 其中 0
表示不返回下级行政区,1
表示返回下一级行政区,2
表示返回下两级行政区,3
表示返回下三级行政区。
在
getAllAdCode
方法中,小编直接把全国与省市区三级的行政编码一次性全部获取回来了,然后再通过循环去找到对应的数据,高德返回全国区域的行政编码其实是非常快的。记得初次写得时候,小编是根据数据中需要哪个区域的数据就去查询那个区域,少量数据的话这样子是没有问题的,但是一旦数据量开始变多,并且查询的不是省级,是市级或者区级,那性能就嘎嘎往下掉。。。-.-
不同颜色标注
那么,现在地图中红色板块的标注就是根据”数据”来控制的了,但是全部都是红色的略显单调,小编这就来给它们分别上上色(✪ω✪)。
在官方文档中对于板块的样式调整有六个参数可以使用,应该是足够满足我们实际中复杂的业务需求了。
具体过程如下:
<script>
export default {
...
methods: {
...,
/** @name 绘制区域地图 **/
drawAreaMap() {
...
const instance = new window.AMap.DistrictLayer.Province({
adcode,
depth: 0,
styles: {
// 填充色
'fill': fillParams => {
console.log(fillParams)
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
const color = `rgba(${r}, ${g}, ${b}, 0.8)`;
return adcode.includes(`${fillParams.adcode}`) ? color : undefined;
},
},
});
instance.setMap(this.map);
},
}
}
</script>
以上小编通过填充色 fill
支持的 Function
类型来实现不同颜色的标注,在回调函数中我们能获取到每个区域板块的行政编码。
省市区板块标注切换
上面我们标注的区域都是以省级为单位的,那么如何实现省级、市级、区级之间的标注切换呢?接下来请听小编细细道来(✪ω✪)。
前面我们知道了标注一块区域就需要知道这块区域的行政编码才行,那么问题转换成:
- 省级:获取需要的省级行政编码
- 市级:获取需要的市级行政编码
- 区域:获取需要的区级行政编码
而且我们在上面的 allAdCode
变量中存储了全国所有区域板块的行政编码,它是一棵树形结构。
我们先看效果,再具体看编码过程:
<template>
<div class="map">
<div id="container" />
<select v-model="range" @change="rangeChange">
<option :value="'province'">省级</option>
<option :value="'city'">市级</option>
<option :value="'area'">区级</option>
</select>
</div>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
import data from './data.js';
let instance = null;
export default {
data() {
return {
// map:null,
range: 'province'
}
},
...
methods: {
...,
/** @name 显示范围改变 **/
rangeChange() {
this.drawAreaMap();
},
/** @name 绘制区域地图 **/
drawAreaMap() {
const allAdCode = await this.getAllAdCode();
// 将树形转换成对象形式
const allAdCodeMap = this.transformTree(allAdCode);
// 获取行政编码
const adcode = [];
data.forEach(address => {
if (this.range === 'province') {
adcode.push(allAdCodeMap[address.province]?.adcode || '');
}
if (this.range === 'city') {
// 处理直辖市
const directCity = [
{ label: '北京市', value: '110000' },
{ label: '天津市', value: '120000' },
{ label: '重庆市', value: '500000' },
{ label: '上海市', value: '310000' },
{ label: '香港特别行政区', value: '810000' },
];
const target = directCity.find(item => item.label === address.province);
if (target) {
adcode.push(target.value);
} else {
adcode.push(allAdCodeMap[address.city]?.adcode || '');
}
}
if (this.range === 'area') {
adcode.push(allAdCodeMap[address.area]?.adcode || '');
}
});
// 重新绘制需要清空图层
instance && instance.setMap(null);
const depth = {
province: 0,
city: 1,
area: 2,
};
instance = new window.AMap.DistrictLayer.Province({
adcode,
depth: depth[this.range], // 设定数据的层级深度: https://lbs.amap.com/api/javascript-api-v2/documentation#districtlayer
styles: {
'fill': fillParams => {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
const color = `rgba(${r}, ${g}, ${b}, 0.8)`;
return adcode.includes(`${fillParams.adcode}`) ? color : undefined;
},
},
});
instance.setMap(this.map);
},
/** @name 将树形的行政编码转成对象形式 **/
transformTree(allAdCode) {
let allAdCodeMap = {};
if (this.range === 'province') {
allAdCodeMap = allAdCode.districtList.reduce((result, province) => {
result[province.name] = province;
return result;
}, {});
}
if (this.range === 'city') {
data.forEach(address => {
const province = allAdCode.districtList.find(
item => item.name === address.province,
);
if (province && province.districtList) { // 注意台湾省数据没有districtList
const cityMap = province.districtList.reduce((result, city) => {
result[city.name] = city;
return result;
}, {});
allAdCodeMap = {
...allAdCodeMap,
...cityMap,
}
}
})
}
if (this.range === 'area') {
data.forEach(address => {
const province = allAdCode.districtList.find(
item => item.name === address.province,
);
if (province && province.districtList) {
const city = province.districtList.find(
item => item.name === address.city,
);
if (city && city.districtList) {
const areaMap = city.districtList.reduce((result, area) => {
result[area.name] = area;
return result;
}, {});
allAdCodeMap = {
...allAdCodeMap,
...areaMap,
};
};
}
});
};
return allAdCodeMap;
},
}
}
</script>
编码过程不难,主要需要注意两点问题,其一是特殊省份像直辖市、台湾省、澳门等等,其二是性能问题。
主题风格切换
最后,我们再来完成一个地图主题风格切换的功能,高德地图官方给我们提供了十种标准的主题,可以直接免费使用,如果还不能满足你的需求,你也可以创建自定义的主题地图,当然,自定义功能强大只是需要花点 Money
(✪ω✪)。传送门
因为比较简单,小编就直接来贴代码啦。
<template>
<div class="map">
...
<select v-model="style" @change="styleChange">
<option v-for="item in styleOptions" :key="item.value" :value="item.value">
{{ item.label }}
</option>
</select>
</div>
</template>
<script>
...
export default {
data() {
return {
...,
style: 'normal',
styleOptions: [
{ label: '标准', value: 'normal' },
{ label: '幻影黑', value: 'dark' },
{ label: '月光银', value: 'light' },
{ label: '远山黛', value: 'whitesmoke' },
{ label: '草色青', value: 'fresh' },
{ label: '雅士灰', value: 'grey' },
{ label: '涂鸦', value: 'graffiti' },
{ label: '马卡龙', value: 'macaron' },
{ label: '靛青蓝', value: 'blue' },
{ label: '极夜蓝', value: 'darkblue' },
{ label: '酱籽', value: 'wine' },
]
}
},
...
methods: {
...,
/** @name 初始化地图 **/
initMap() {
return new Promise(resolve => {
window._AMapSecurityConfig = {
securityJsCode: '你的安全密钥',
}
AMapLoader.load({
key: '你的Key',
version: '2.0',
plugins: [
'AMap.DistrictSearch'
],
}).then((AMap)=>{
this.map = new AMap.Map('container', {
center: [110.17293, 35.20173],
zoom: 4.8,
mapStyle: 'amap://styles/' + this.style, // 加载主题
});
this.map.on('complete', () => {
resolve();
});
}).catch(e=>{
console.log(e);
})
})
},
/** @name 主题风格切换 **/
async styleChange() {
await this.initMap();
this.drawAreaMap();
},
}
}
</script>
具体实现效果:
哎,写到这里突然发现文章好像又贼拉长了,还有两个功能没写呢(“工具栏操作”、“地图板块交互事件”),呃……后面再写续集吧,溜了溜了。
完整源码
至此,本篇文章就写完啦,撒花撒花。
希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。