1.申请成为百度认证开发者并创建一个浏览器端应用token用于使用百度JavaScript API,申请ak;
2.申请一个服务端应用token用于调取全球服务接口获取数据,申请ak;
3.基于已创建的服务端token创建工单申请全球服务权限,一般1-3个工作日,可以申请15天试用,申请成功后会把接口文档发到你的邮箱;
4.学习并使用百度地图JavaScript API,也可以在示例中心在线编辑沙盒;
你要实现导航服务,首先就要有个起始点,这两个点可以是用户输入的,也可以是让用户在地图点选,这里就选择点选方式获取起始点,然后用这两个点去查询可行的路线方案,最后再把这些路线分别展示到地图上。很清晰是吧,那我们开始!
我是使用vite创建的vue3项目,直接在index.html
文件中添加
新建一个vue页面,创建地图容器并初始化地图,记得给容器宽高属性:
// 创建一个容器
// 声明一些变量
let bdMap: any = {} // 地图对象
let bdKey: string = '你的ak' // 你自己申请的ak
let startPoint = ref({ point: {}, address: {} }) // 起点
let endPoint = ref({ point: {}, address: {} }) // 终点
// 创建地图方法
// 初始化地图
const initMap = () => {
const map = new BMapGL.Map('map-container')
bdMap = map
const point = new BMapGL.Point(116.404, 39.915) // 设置中心点坐标
map.centerAndZoom(point, 12) // 设置地图级别
map.enableScrollWheelZoom(true) // 开启鼠标滚轮缩放
}
想要实现地图选点,我们要用到两个方法:
1.监听地图点击事件addEventListener()
和移除监听方法removeEventListener()
2.在地图上绘制点标记new BMapGL.Point(lng, lat)
、new BMapGL.Marker()
和addOverlay()
// 根据经纬度创建标记点方法
const drawPoint = (lng: number, lat: number) => {
const defPoint = new BMapGL.Point(lng, lat) // lng 经度 lat 纬度
const marker = new BMapGL.Marker(defPoint) // 创建点标记
map.addOverlay(marker) // 将点添加到地图上
}
// 选择起点
const pickStart = () => {
bdMap.addEventListener('click', handleClick) // 监听点击事件
async function handleClick(e: any) {
const clickP = new BMapGL.Point(e.latlng.lng, e.latlng.lat)
startPoint.value.point = clickP
drawPoint(clickP.lng, clickP.lat) // 绘制选中的起点
bdMap.removeEventListener('click', handleClick) // 移除监听事件
}
}
// 选择终点
const pickEnd = () => {
bdMap.addEventListener('click', handleClick) // 监听点击事件
async function handleClick(e: any) {
const clickP = new BMapGL.Point(e.latlng.lng, e.latlng.lat)
endPoint.value.point = clickP
drawPoint(clickP.lng, clickP.lat) // 绘制选中的终点
bdMap.removeEventListener('click', handleClick) // 移除监听事件
}
}
有了起始点经纬度我们就可以调用路线规划接口来查看返回的数据
http://api.map.baidu.com/direction_abroad/v1/driving?origi n=40.702963,-73.907852&destination=40.625416,-73.960852&ak =您的 AK //GET 请求
参数origin
表示起点经纬度
参数destination
表示终点经纬度
返回的数据结构是这样的:
├── routes # 返回的方案集
│ └── destination # 终点经纬度({ lat, lng })
| └── origin # 起点经纬度({ lat, lng })
| └── distance # 距离(单位:米)
| └── light_number # 该路段红绿灯总个数
| ├── steps # 路线分段数组
| | └── instructions # 分段的导航信息
| | └── direction # 进入道路的角度(枚举值)
| | └── turn # 机动转向点(枚举值)
| | └── distance # step 的距离信息(单位:米)
| | └── road_name # 分段的道路名称
| | └── start_location # 分段起点经纬度({ lat, lng })
| | └── end_location # 分段终点经纬度({ lat, lng })
| | └── path # 分段坐标(lng1, lat1;lng2, lat2;...)
注意:其他完整传参和返回值可以在申请全球服务成功后邮箱接收到的接口文档中查阅
贴一张请求结果示例
观察返回结果可以发现,我们更关注的其实是steps中的信息,其中有个path属性,它以字符串的形式存储了经纬度信息,各点位间通过;
分隔,即该方案各路段的线段坐标信息。你可以直接遍历这些路段的path拿到经纬度分段绘制线要素,我这里的需求是要合并后绘制成一整条路线,所以做了简单的处理:
const routes = [...res.data.result.routes] // 取出结果中的方案信息
// 这个方法是往每一个方案里添加了paths参数,即合并多路段经纬度
const routerPaths = routes.map((item: { paths: any; steps: any }) => {
item.paths = dealPaths(item.steps)
return item
})
// 将路线规划返回值中的路段数据合并成一条方法
function dealPaths(steps: any[]) {
// 将path参数合并成一条经纬度字符串,用';'连接
const pathsStr = steps.reduce((pre: any, cur: any) => {
const split = pre ? ';' : ''
return pre + split + cur.path
}, '')
// 将路径经纬度字符串分割处理成经纬度数组
const newPaths = [...new Set(pathsStr.split(';'))] // 将不同路段首尾相连重复的点位过滤掉
return newPaths
}
通过这个处理我们就将原本的多条path'lng1, lat1;lng2, lat2;...'
数据处理成一条['lng1, lat1', 'lng2, lat2', ...]
绘制时:
// 此处paths即上面处理好的格式
const paths = paths.map((item: string) => {
const latlng = item.split(',')
return new BMapGL.Point(latlng[0], latlng[1])
})
// 创建线要素
const polyline = new BMapGL.Polyline(paths, {
strokeColor: 'green',
strokeWeight: 4,
strokeOpacity: 0.5
})
bdMap.addOverlay(polyline) // 将线添加到地图上
至此,就完成了基础的境外路线规划功能,可以在地图上选起始点调取WebAPI接口获取路线信息然后绘制路线。
最终结果如下图:
附上完整项目地址,感兴趣可以拉代码直接运行,代码中用到的的境外导航token需要换成自己申请的。
如果是要直接在中国大陆境内使用导航的话可以直接使用sdk提供的方法,选择起始点还是用上面的方法,传参给以下方法就可以直接使用,调用这个方法会自动生成起始点图标和路径,通过配置参数还能默认将视角定位到此处,非常方便。
// 中国大陆导航
const navDriving = () => {
if (!navPointUsable()) return
const driving = new BMapGL.DrivingRoute(bdMap, {
renderOptions: { map: bdMap, autoViewport: true }
})
driving.search(startPoint.value.point, endPoint.value.point)
}
注意:此接口默认只支持中国大陆范围内查询,要查询全球数据同样需要申请“全球逆地理编码服务”权限
此处用到了v3版本的WebAPI,调取此接口可以传入经纬度获取此处位置信息,包括国家、省份、街道等,国外的基本可用的就是这些信息,国内经纬度还会有更多可选信息。
// 全球逆地理编码 根据经纬度获取位置名称
const getWorldAddress = async (point: { lat: any; lng: any }) => {
let result = {}
const { lat, lng } = point
// 这里的sbaidu在项目中配置了代理,直接调用换成https://api.map.baidu.com
const url = `/sbaidu/reverse_geocoding/v3/?ak=${bdKey}&output=json&coordtype=wgs84ll&location=${lat},${lng}`
await axios.get(url).then((res: any) => {
result = res.result
const { formatted_address, addressComponent } = res.data.result
const { country } = addressComponent
result = { formatted_address, country }
})
return result
}
传参和返回数据详情描述可查阅官方文档。
我们点选获取起始点或者切换规划路线时,会用到清除图层的方法,如下:
// 不传参直接移除所有图层,可通过传参控制删除指定图层,具体参看api文档
map.clearOverlays()
// 只是隐藏所有图层并没有清除,可控制图形要素、矢量服务、影像服务等显示/隐藏
map.setDisplayOptions({
overlay: false // 可选:true 显示所有图层
})
实际开发时还会有其他需求,如自定义图标、播放导航动画等等,具体就要自己去查阅API文档学习了,对你有帮助的话点个赞再走吧。