前言
- 很多项目中都会使用到地图,使用的地图基本都是百度、高德、腾讯这些,但是,使用步骤都是大差不差的;
- 就以高德为例,说一下基本的使用流程;
- 下面是使用高德地图的基本流程:
- 注册账号 申请
Key
和安全密钥
;- 有了这两个东西,才能去使用高德地图的
API
;
- 有了这两个东西,才能去使用高德地图的
- 使用高德地图提供的
jsloader
去加载高德地图的js文件,让它加载到我们的页面中; - 加载好资源之后,再使用高德地图的API初始化地图;
- 配置地图风格和缩放比例;
- 绘制路线和当前所在位置;
- 注册账号 申请
- 本篇文章使用的是
Vue3 + TS
为例写的;
一、准备工作
1.1 注册账号 成为 开发者 获取 Key 和 安全密钥
- 去高德开放平台注册账号、实名认证等;
- 实名认证完成之后,点击控制台;
- 选择 应用管理 ➡ 我的应用 ➡ 创建新应用 ➡ 填写 应用名称 并选择 应用类型 ;
- 创建好应用之后,点击右边的 添加Key ,按照要求填写信息;
- ❗❗ Key名称最好是用英文;
- ❗❗ 注意 :
- 服务平台 一项 请选择 Web 端 (JSAPI) ;
- 点击提交之后,应用就创建成功了,我们所需要的 Key 和 安全密钥 也就有了;
二、接入高德地图 - JSAPI的加载
2.1 安装高德地图所需的loader
- 🎯 JS API 的加载 🎯;
- 命令:
pnpm add @amap/amap-jsapi-loader --save
;npm i @amap/amap-jsapi-loader --save
;
2.2 初始化地图
- 初始化 高德地图:
- 高德地图的初始化会操作 DOM ;
- 所以,初始化地图的时机应当是在 组件渲染完毕之后 再进行初始化操作;
Vue3
:
onMounted()
;Vue2
:
mounted()
;
-
开始使用:
tsimport { onMounted } from 'vue'; import AMapLoader from '@amap/amap-jsapi-loader'; // 开发环境:配置JsCode // 如果是在 ts 的项目中,这一步会有类型错误,解决方案请移步 2.1.1 window._AMapSecurityConfig = { securityJsCode:'「您申请的安全密钥」' }; /** 初始化地图函数 */ onMounted(() => { // AMapLoader => 加载器 // 资源加载完成后就会触发 then AMapLoader.load({ "key": "上述步骤得到的key", // 申请好的Web端开发者Key,首次调用 load 时必填 "version": "2.0", // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15 "plugins": [], // 需要使用的的插件列表,如比例尺'AMap.Scale'等 }).then((AMap)=>{ // 初始化地图 const map = new AMap.Map('放置地图的div容器id', { // 配置对象 - 配置地图的风格和缩放比例,请移步 2.2 }); }).catch(e => { console.log(e); }); });
-
效果展示:
- 这就是基本的地图;
- 这就是基本的地图;
2.1.1 解决 window._AMapSecurityConfig 的类型错误
-
给
window
扩展 全局属性; -
目标文件 :
src/types/global.d.ts
;
tsinterface Window { _AMapSecurityConfig: { securityJsCode: string; }; }
- 这里为什么使用
interface
?- 我们可以按住
Ctrl
,鼠标点击window
,会跳转到lib.dom.d.ts
文件; - 再按住
Ctrl
,点击window
; - 就会跳转到
Window
的类型声明处; - 我们可以看到,此处使用的是
interface
,现在我们是想给Window
上添加类型,使用interface
的话,可以重复声明类型,这些重复的类型最后是会合并在一起的;
- 我们可以按住
2.2 调节地图的风格 和 缩放比例
- 🎯 使用官方地图样式 🎯;
- 在上述代码的基础上进行配置:
ts
const map = new AMap.Map('容器id', {
// 地图风格 - 可以修改地址的最后一个单词来使用不同的风格
mapStyle: 'amap://styles/whitesmoke',
// 缩放比例 - 缩放比例越大,地图就越大,展示的月清晰
zoom: 10
});
- 地图创建之后使用Map对象的setMapStyle方法来修改
map/setMapStyle('amap://styles/whitesmoke')
- 可以修改
mapStyle
属性值 的 最后一个单词 来 使用不同的风格; - 可以打开官网 🎯 使用官方地图样式 🎯 去选择项目需要的地图风格;
- 高德地图 JS API 2.0
- 参考手册
三、自定义绘制轨迹
- 必须要有 起点 和 终点 的 经纬度坐标;
- 根据地图的自动规划功能,就会得到一条行车路线;
- 地图自动规划的行车路线可能和我们所需要的路线有差别,在项目当中,接口会返回一组由经纬度坐标组成的数组,这时就需要根据经纬度坐标去做细微的绘制;
- 就按照最常使用的物流来说,接口会返回起点、终点坐标,然后就是我们的快递具体到了哪一个中转站,这个中转站会上传当前位置的经纬度坐标,我们根据得到的坐标进行绘制即可;
3.1 使用起点、终点坐标绘制基本路线
- 先根据接口得到的起点和终点坐标,根据地图的自动绘制功能,绘制基本路线;
- 基于上述代码:
ts
// 我们将接口将返回的经纬度数组赋值给 longitudeAndLatitudeList 响应式数据;
// 这里就是模拟一下
const logisticsInfoList = ref([
{latitude: '23.129152403638752', longitude: '113.42775362698366'},
{latitude: '30.454012', longitude: '114.42659'},
{latitude: '31.93182', longitude: '118.633415'},
{latitude: '31.035032', longitude: '121.611504'}
]);
const initMap = () => {
AMapLoader.load({
"key": "上述步骤得到的key", // 申请好的Web端开发者Key,首次调用 load 时必填
"version": "2.0", // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15
"plugins": [], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then((AMap) => {
// 初始化地图
const map = new AMap.Map('map', {
// 地图风格
mapStyle: 'amap://styles/whitesmoke',
// 缩放比例
zoom: 12
});
// 加载插件 - AMap.Drivin
AMap.plugin('AMap.Driving', function () {
// 插件加载完成后,初始化 Driving 实例
const driving = new AMap.Driving({
// 使用上面得到的地图实例,表示,路径是画在我们当前初始化的这个地图上的
map
});
// 得到 Driving 实例之后,就可以使用 driving.search() 方法,通过起点和终点绘制路径
// 此处最好不要使用 logisticsInfoList 响应式数据进行地图绘制;
// 重新声明一个变量,复制一份经纬度数据
// 有可能我们的经纬度数据是没有的,所以在这块需要进行判断,并且必须 logisticsInfoList.value.length >= 2(必须要有起点 和 终点坐标)
if (logisticsInfoList?.value && logisticsInfoList.value.length >= 2) {
const list = [...logisticsInfoList.value];
// 取出 起点、终点、途径点
const start = list.shift();
const end = list.pop();
// 剩下的list就是途径点
// 该函数接收第四个参数
// 第一个参数:由起点经纬度组成的数组
// 第二个参数:由终点经纬度组成的数组
// 第三个参数:配置对象 - 请移步 3.3
// 第四个参数:函数 - 执行了该函数,就表示路径已经规划完成
driving.search(
[start?.longitude, start?.latitude],
[end?.longitude, end?.latitude],
() => {
// 规划完毕
}
);
};
});
})
.catch(e => {
console.log(e);
});
};
- 注意 :
- 在Vue3项目中,不要直接使用接口返回的经纬度坐标数组,
- 该数组通常都是我们使用ref声明的数据进行接收的,如果依然使用该数据的话,页面会受影响的;
- 正确的做法应该是:重新声明一个变量,去复制一份经纬度数组;
- 效果展示:
3.2 关闭实时路况信息
ts
const driving = new AMap.Driving({
map,
// 关闭实时路况信息
showTraffic: false
});
- 效果展示:
3.3 根据途径点自定义绘制路径
ts
driving.search(
[start?.longitude, start?.latitude],
[end?.longitude, end?.latitude],
// waypoints:该属性的属性值为由经纬度数组组成的数组,也就是说该属性的属性值是个二维数组
{ waypoints: list.map((item) => [item.longitude, item.latitude]) },
() => {
// 执行了这个函数,就表示路径已经规划完毕
}
);
- 效果展示:
3.4 关闭沿途标记点
ts
const driving = new AMap.Driving({
// 使用上面得到的地图实例,表示,路径是画在我们当前初始化的这个地图上的
map,
// 关闭实时路况信息
showTraffic: false,
// 关闭途径点icon
hideMarkers: true
});
- 效果展示:
- 问题 :
- 关闭途径点之后,起点和终点的标志也就不显示了;
- 请看下节;
四、绘制 标记 以及 当前位置
4.1 绘制标记
4.1.1 ❌ 直接使用图片的URL
- ❗❗ 缺陷 :
- 按照这种方式设置的标记点是 无法调整
icon
的大小; - 图片多大,标记显示的就是多大;
- 按照这种方式设置的标记点是 无法调整
ts
import startImg from '@/assets/images/start.png';
// 取出 起点、终点、途径点
const start = list.shift();
// 创建起点
const marker = new AMap.Marker({
// 经纬度坐标
position: [start?.longitude, start?.latitude],
// 需要展示的图标
icon: startImg
});
// 将创建的标记点加到地图上(此处的map就是上述创建的地图实例)
map.add(marker);
- 缺陷 :
- 标记点虽然绘制上了,但是标记点和大小和位置不对,但是这种方式不支持设置图片的样式;
4.1.2 ✅ 创建 AMap.Icon 实例 绘制标记
- 优点 :
- 可以设置图标的大小
size
,偏移imageOffset
等属性,比单纯设置URL更具灵活性;
- 可以设置图标的大小
ts
import startImg from '@/assets/images/start.png';
// 取出 起点、终点、途径点
const start = list.shift();
// 创建起点
const icon = new AMap.Icon({
// 图标尺寸 ===> new AMap.Size(宽, 高)
size: new AMap.Size(25, 30),
// Icon图片
image: startImg,
// 根据所设置的大小拉伸或压缩图片 ===> new AMap.Size(宽, 高)
imageSize: new AMap.Size(25, 30)
});
const marker = new AMap.Marker({
// 经纬度坐标
position: [start?.longitude, start?.latitude],
// 需要展示的图标
icon
});
// 将创建的标记点加到地图上(此处的map就是上述创建的地图实例)
map.add(marker);
- 效果展示:
4.1.3 设置图标的偏移
- 不管是使用哪种方式设置的标记,都可以发现,图像的左上角和我们的起点位置是重合的;
- 设置偏移量的话,就将图片向左偏移宽度的一半,向上偏移高度的100%即可;
ts
const marker = new AMap.Marker({
// 经纬度坐标
position: [start?.longitude, start?.latitude],
// 需要展示的图标
icon,
// 设置偏移量 ===> new AMap.Pixel(X轴方向的偏移量, Y轴方向的偏移量)
offset: new AMap.Pixel(-12.5, -30)
});
- 效果展示:
4.2 封装绘制标记函数
-
由于我们代码的标记不止一处,我们可以将绘制标记的代码封装成一个函数,使用的时候,直接传递经纬度,图片的地址,大小,偏移量等等;
-
类型文件:
ts// 文件路径:src/types/order.d.ts export type Location = { /** 经度 */ longitude: string; /** 纬度 */ latitude: string; };
-
封装绘制标记函数:
- 注意点 :
- 要将该函数封装在
AMapLoader.load
的then
回调中;
- 要将该函数封装在
tsimport type { Location } from '@/types/order'; import startImg from '@/assets/start.png'; /** * 创建标记函数 * @param point 经纬度坐标 * @param image 图片 * @param width 图片宽度 * @param height 图片高度 */ const createMarker = ( point: Location, image: string, width: number = 25, height: number = 30 ) => { // 创建icon实例 const icon = new AMap.Icon({ // 图标尺寸 ===> new AMap.Size(宽, 高) size: new AMap.Size(width, height), // Icon图片 image, // 根据所设置的大小拉伸或压缩图片 ===> new AMap.Size(宽, 高) imageSize: new AMap.Size(width, height) }); // 创建标记 const marker = new AMap.Marker({ // 经纬度坐标 position: [point?.longitude, point?.latitude], // 需要展示的图标 icon, // 图像相对展示区域的偏移量 ===> new AMap.Pixel(X轴方向的偏移量, Y轴方向的偏移量) offset: new AMap.Pixel(-width / 2, -height) }); return marker; };
- 注意点 :
-
使用函数:
ts// 取出 起点、终点、途径点 const start = list.shift(); // 将创建的标记点加到地图上 // 这块会提示start可能不存在,使用 ! 进行非空断言 map.add(createMarker(start!, startImg, 25, 30));
-
效果展示:
4.3 标记当前所在位置
ts
// 当前位置坐标
// 我这里就是模拟,实际的项目中,也是通过接口返回的
// 绘制当前位置的时机,最好是在路径已经规划完毕之后再去绘制
import carImg from '@/assets/car.png';
const currentLocationInfo = ref({"latitude":"31.93182","longitude":"118.633415"});
ts
driving.search(
[start?.longitude, start?.latitude],
[end?.longitude, end?.latitude],
{ waypoints: list.map((item) => [item.longitude, item.latitude]) },
() => {
// 执行了这个函数,就表示路径已经规划完毕
// 绘制当前位置,最好是在路径规划完成之后绘制
// 获取当前点位
const curr = currentLocationInfo.value;
map.add(createMarker(curr!, carImg, 25, 20));
}
);
- 效果展示:
4.4 调整当前位置到地图正中央及调整缩放比例
- 🎯 参考手册 🎯
- 调整当前位置 ;
- 让当前位置显示在地图的正中央;
setFitView()
;
- 调整缩放比例 ;
- 路线更加清晰
setRoom()
;
ts
driving.search(
[start?.longitude, start?.latitude],
[end?.longitude, end?.latitude],
{ waypoints: list.map((item) => [item.longitude, item.latitude]) },
() => {
// 执行了这个函数,就表示路径已经规划完毕
// 绘制当前位置,最好是在路径规划完成之后绘制
// 获取当前点位
const curr = logistics.value?.currentLocationInfo;
const currMarker = createMarker(curr!, carImg, 25, 20);
map.add(currMarker);
// 先展示整个路径,三秒后定位到地图的正中央
setTimeout(() => {
// 定位到地图正中央
// 第一个参数,是有 marker 组成的数组
map.setFitView([currMarker]);
// 设置缩放比例
map.setZoom(10);
}, 3000);
}
);
- 效果展示: