- 作者:老汪软件技巧
- 发表时间: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 })
})
})
结语
感觉跳转到高德是个挺常见的操作。