• 作者:老汪软件技巧
  • 发表时间:2024-10-10 21:03
  • 浏览量:

引言

应用中显示路径以及跳转到高德导航是很常见的一个操作,这里分享一下基本实现流程。

主要组件及API介绍

在实现路径规划功能时,我们将使用以下几个关键组件和技术:

1. 变量准备

准备存储开始,结束地址的变量,符合地图组件类型的结构,用于跳转高德的want参数。

@State startAddress: string = ''
@State endAddress: string = ''
// 地图相关
private mapOptions?: mapCommon.MapOptions;
private callback?: AsyncCallbackMapComponentController>;
private mapController?: map.MapComponentController;
private mapEventManager?: map.MapEventManager;
// 起点
@State start: mapCommon.LatLng = {
  latitude: 31.2304,
  longitude: 121.4737
}
// 终点
@State end: mapCommon.LatLng = {
  latitude: 39.9042,
  longitude: 116.4074
}
@State cameraUpdate: map.CameraUpdate = map.zoomTo(5);
@State want: Want = {
  uri: `amapuri://route/plan?sid=BGVIS1&dlat=${this.end.latitude}&dname=${this.endAddress}&slat=${this.start.latitude}&dlon=${this.end.longitude}&did=BGVIS2&slon=${this.start.longitude}&sname=${this.startAddress}&t=0`
}
context = getContext(this) as common.UIAbilityContext
// 调用MapComponent组件初始化地图
MapComponent({ mapOptions: this.mapOptions, mapCallback: this.callback }).width('100%').height('100%')

2. 获取经纬度

为了进行路径规划,首先需要将用户输入的起始和结束地址转换为经纬度。我们可以使用高德地图API或鸿蒙的site.geocode接口来实现。

高德API实现:

高德API需要注册开发者获取key,这里就不展示具体的网络请求了

//高德api获取经纬度
async getLatLng(address: string) {
  const res = await getAmapLatLng(address)  //封装好的网络请求
  const data = res.data.geocodes as Geocode[]
  // AlertDialog.show({ message: JSON.stringify(res, null, 2) })
  return data[0].location.split(',')
}
async getAllLatLng() {
  //高德API:
  const res = await this.getLatLng(this.startAddress) as string[]
  this.start.longitude = Number(res[0])
  this.start.latitude = Number(res[1])
  const res2 = await this.getLatLng(this.endAddress) as string[]
  this.end.longitude = Number(res2[0])
  this.end.latitude = Number(res2[1])
  this.canToAmap = true
}

鸿蒙site:

async getAllLatLng() {
  const hmRes1 = await site.geocode({ query: this.startAddress })
  const hmRes2 = await site.geocode({ query: this.endAddress })
  if (hmRes1.sites && hmRes2.sites) {
    this.start.longitude = Number(hmRes1.sites[0].location?.longitude)
    this.start.latitude = Number(hmRes1.sites[0].location?.latitude)
    this.end.longitude = Number(hmRes2.sites[0].location?.longitude)
    this.end.latitude = Number(hmRes2.sites[0].location?.latitude)
  }
  this.canToAmap = true
}

这里定义了一个getAllLatLng方法,接收经纬度并赋给状态变量。

2. 初始化地图

在initMap方法中,我们设置了默认地图的中心位置和缩放级别,并定义了一个回调函数,在地图初始化完成后执行必要的操作。

示例代码:

initMap() {
  this.mapOptions = {
    position: {
      target: { latitude: 39.9, longitude: 116.4 },
      zoom: 5
    }
  };
  this.callback = async (err, mapController) => {
    if (!err) {
      this.mapController = mapController; // 获取地图控制器
    }
  };
}

高德地图导航原路返回怎么用_导航默认高德地图_

3. 路径规划实现

路径规划的核心逻辑是使用navi.getDrivingRoutes方法,根据获取到的经纬度计算路径。成功后,我们可以在地图上绘制出规划路径。

获取经纬度:

// 路径规划
async testDrivingRoutes() {
  let params: navi.DrivingRouteParams = {
    // 起点的经纬度
    origins: [this.start],
    // 终点的经纬度
    destination: this.end,
    // 路径的途经点
    // waypoints: this.currents,
    language: "zh_CN"
  };
  // this.mapController.moveCamera(map.zoomTo(16))
  return await navi.getDrivingRoutes(params);
}

地图绘制:

// 地图绘制
async drawRoute() {
  let cameraPosition: mapCommon.CameraPosition = {
    target: {
      longitude: (this.start.longitude + this.end.longitude) / 2,
      latitude: (this.start.latitude + this.end.latitude) / 2
    },
    zoom: 5
  };
  let cameraUpdate: map.CameraUpdate = map.newCameraPosition(cameraPosition);
  this.mapController?.moveCamera(cameraUpdate);
  // promptAction.showToast({ message: '视角移动', bottom: 120 })
  this.isPathDrawnComplete = true
  // 绘制线段
  let markerOptions: mapCommon.MarkerOptions = {
    position: this.start,
    rotation: 0,
    visible: true,
    zIndex: 0,
    alpha: 1,
    anchorU: 0.5,
    anchorV: 1,
    clickable: true,
    draggable: true,
    flat: false
  };
  // 创建Marker
  this.mapController?.moveCamera(this.cameraUpdate)
  await this.mapController?.addMarker(markerOptions);
  const result = await this.testDrivingRoutes()
  // Logger.info(result.routes)
  result.routes[0].steps.forEach(step => {
    step.roads.forEach(road => {
      // road.polyline
      this.mapController?.addPolyline({
        points: road.polyline,
        clickable: true,
        startCap: mapCommon.CapStyle.BUTT,
        endCap: mapCommon.CapStyle.BUTT,
        geodesic: false,
        jointType: mapCommon.JointType.BEVEL,
        visible: true,
        width: 10,
        zIndex: 10,
        gradient: false,
        color: 0xFFFF2737
      });
    })
  })
  this.isPathDrawnComplete = false
  promptAction.showToast({ message: '路径规划完成,可开始导航', bottom: 120 })
}

在drawRoute方法中,我们传入起点和终点的经纬度,调用getDrivingRoutes方法进行路径计算,并在地图上绘制出路径。

4. 生命周期中执行函数

在页面一进入时就执行逻辑应该是比较常见的。

async aboutToAppear() {
    //传参接收地址
    this.startAddress = Data.startAddress
    this.endAddress = Data.endAddress
    //地图初始化
    this.initMap()
    //获取经纬度
    await this.getAllLatLng()
    promptAction.showToast({ message: '计算路径中,请稍等~', bottom: 120 })
    //绘制路线
    await this.drawRoute()
}

5. 跳转到高德地图

完成路径规划后,可以可视化的将路程展示给用户。当然,需要导航时,还是得用高德。

这里使用一开始创建的want生成跳转链接,并通过context的startAbility方法打开高德地图进行导航。

示例代码:

.onClick(() => {
  // this.mapController.moveCamera(this.cameraUpdate)
  // this.isAppBExist()
  this.want.uri =
    `amapuri://route/plan?sid=BGVIS1&dlat=${this.end.latitude}&dname=${this.endAddress}&slat=${this.start.latitude}&dlon=${this.end.longitude}&did=BGVIS2&slon=${this.start.longitude}&sname=${this.startAddress}&t=0`
  this.context.startAbility(this.want, (err: BusinessError) => {
    if (err.code) {
      promptAction.showToast({
        message: `startAbility failed,code is ${err.code},message is ${err.message}`,
        bottom: 120
      })
      return
    }
    // promptAction.showToast({ message: 'startAbility succeed', bottom: 120 })
  })
})

结语

感觉跳转到高德是个挺常见的操作。