likes
comments
collection
share

前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

作者站长头像
站长
· 阅读数 2

前言

  • 很多项目中都会使用到地图,使用的地图基本都是百度、高德、腾讯这些,但是,使用步骤都是大差不差的;
  • 就以高德为例,说一下基本的使用流程;
  • 下面是使用高德地图的基本流程:
    • 注册账号 申请 Key安全密钥
      • 有了这两个东西,才能去使用高德地图的API
    • 使用高德地图提供的jsloader去加载高德地图的js文件,让它加载到我们的页面中;
    • 加载好资源之后,再使用高德地图的API初始化地图;
    • 配置地图风格和缩放比例;
    • 绘制路线和当前所在位置;
  • 本篇文章使用的是Vue3 + TS为例写的;

一、准备工作

1.1 注册账号 成为 开发者 获取 Key 和 安全密钥

  • 去高德开放平台注册账号、实名认证等;
  • 实名认证完成之后,点击控制台;
  • 选择 应用管理我的应用创建新应用 ➡ 填写 应用名称 并选择 应用类型
    • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
    • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
    • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
  • 创建好应用之后,点击右边的 添加Key,按照要求填写信息;
    • ❗❗ Key名称最好是用英文;
    • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
    • ❗❗ 注意
      • 服务平台一项 请选择 Web 端 (JSAPI)
      • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
  • 点击提交之后,应用就创建成功了,我们所需要的 Key安全密钥 也就有了;
    • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

二、接入高德地图 - JSAPI的加载

2.1 安装高德地图所需的loader

2.2 初始化地图

  • 初始化 高德地图:
    • 高德地图的初始化会操作 DOM
    • 所以,初始化地图的时机应当是在 组件渲染完毕之后 再进行初始化操作;
    • Vue3
      • onMounted()
    • Vue2
      • mounted()
  • 开始使用:
    import { 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);
        });
    });
    
  • 效果展示:
    • 这就是基本的地图; 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

2.1.1 解决 window._AMapSecurityConfig 的类型错误

  • window 扩展 全局属性
  • 目标文件
    • src/types/global.d.ts
    interface Window {
        _AMapSecurityConfig: {
            securityJsCode: string;
        };
    }
    
    • 这里为什么使用 interface
      • 我们可以按住 Ctrl,鼠标点击 window,会跳转到lib.dom.d.ts文件;
      • 再按住 Ctrl,点击 window
        • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
      • 就会跳转到Window的类型声明处;
        • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
      • 我们可以看到,此处使用的是interface,现在我们是想给Window上添加类型,使用interface的话,可以重复声明类型,这些重复的类型最后是会合并在一起的;

2.2 调节地图的风格 和 缩放比例

const map = new AMap.Map('容器id', {
    // 地图风格 - 可以修改地址的最后一个单词来使用不同的风格
    mapStyle: 'amap://styles/whitesmoke',
    // 缩放比例 - 缩放比例越大,地图就越大,展示的月清晰
    zoom: 10
});
  • 地图创建之后使用Map对象的setMapStyle方法来修改
  • map/setMapStyle('amap://styles/whitesmoke')

三、自定义绘制轨迹

  • 必须要有 起点终点经纬度坐标
  • 根据地图的自动规划功能,就会得到一条行车路线;
  • 地图自动规划的行车路线可能和我们所需要的路线有差别,在项目当中,接口会返回一组由经纬度坐标组成的数组,这时就需要根据经纬度坐标去做细微的绘制;
  • 就按照最常使用的物流来说,接口会返回起点、终点坐标,然后就是我们的快递具体到了哪一个中转站,这个中转站会上传当前位置的经纬度坐标,我们根据得到的坐标进行绘制即可;

3.1 使用起点、终点坐标绘制基本路线

  • 先根据接口得到的起点和终点坐标,根据地图的自动绘制功能,绘制基本路线;
  • 基于上述代码:
// 我们将接口将返回的经纬度数组赋值给 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声明的数据进行接收的,如果依然使用该数据的话,页面会受影响的;
      • 正确的做法应该是:重新声明一个变量,去复制一份经纬度数组;
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

3.2 关闭实时路况信息

const driving = new AMap.Driving({
    map,
    // 关闭实时路况信息
    showTraffic: false
});
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

3.3 根据途径点自定义绘制路径

driving.search(
    [start?.longitude, start?.latitude],
    [end?.longitude, end?.latitude],
    // waypoints:该属性的属性值为由经纬度数组组成的数组,也就是说该属性的属性值是个二维数组
    { waypoints: list.map((item) => [item.longitude, item.latitude]) },
    () => {
        // 执行了这个函数,就表示路径已经规划完毕
    }
);
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

3.4 关闭沿途标记点

const driving = new AMap.Driving({
    // 使用上面得到的地图实例,表示,路径是画在我们当前初始化的这个地图上的
    map,
    // 关闭实时路况信息
    showTraffic: false,
    // 关闭途径点icon
    hideMarkers: true
});
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
  • 问题
    • 关闭途径点之后,起点和终点的标志也就不显示了;
    • 请看下节;

四、绘制 标记 以及 当前位置

4.1 绘制标记

4.1.1 ❌ 直接使用图片的URL

  • ❗❗ 缺陷
    • 按照这种方式设置的标记点是 无法调整icon的大小
    • 图片多大,标记显示的就是多大;
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);
  • 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
  • 缺陷
    • 标记点虽然绘制上了,但是标记点和大小和位置不对,但是这种方式不支持设置图片的样式;

4.1.2 ✅ 创建 AMap.Icon 实例 绘制标记

  • 优点
    • 可以设置图标的大小size,偏移imageOffset等属性,比单纯设置URL更具灵活性;
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);
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

4.1.3 设置图标的偏移

  • 不管是使用哪种方式设置的标记,都可以发现,图像的左上角和我们的起点位置是重合的;
  • 设置偏移量的话,就将图片向左偏移宽度的一半,向上偏移高度的100%即可;
const marker = new AMap.Marker({
    // 经纬度坐标
    position: [start?.longitude, start?.latitude],
    // 需要展示的图标
    icon,
    // 设置偏移量 ===> new AMap.Pixel(X轴方向的偏移量, Y轴方向的偏移量)
    offset: new AMap.Pixel(-12.5, -30)
});
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

4.2 封装绘制标记函数

  • 由于我们代码的标记不止一处,我们可以将绘制标记的代码封装成一个函数,使用的时候,直接传递经纬度,图片的地址,大小,偏移量等等;
  • 类型文件:
    // 文件路径:src/types/order.d.ts
    export type Location = {
        /** 经度 */
        longitude: string;
        /** 纬度 */
        latitude: string;
    };
    
  • 封装绘制标记函数:
    • 注意点
      • 要将该函数封装在 AMapLoader.loadthen 回调中;
    import 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;
    };
    
  • 使用函数:
    // 取出 起点、终点、途径点
    const start = list.shift();
    // 将创建的标记点加到地图上
    // 这块会提示start可能不存在,使用 ! 进行非空断言
    map.add(createMarker(start!, startImg, 25, 30));
    
    前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

4.3 标记当前所在位置

// 当前位置坐标
// 我这里就是模拟,实际的项目中,也是通过接口返回的
// 绘制当前位置的时机,最好是在路径已经规划完毕之后再去绘制
import carImg from '@/assets/car.png';
const currentLocationInfo = ref({"latitude":"31.93182","longitude":"118.633415"});
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));
    }
);
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置

4.4 调整当前位置到地图正中央及调整缩放比例

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);
    }
);
  • 效果展示: 前端开发 - 【Vue】 - 前端项目 接入 高德地图、绘制轨迹、起点终点、当前位置