百度地图基于react实现

背景需求

在某一次需求中被要求,研发一个地图页面,能够具备搜索定位,自动定位,地图与标记拖移的功能,并且要求使用百度地图研发。
因为项目使用的是react,因为习惯性的搜索react百度地图,现网其实有成熟的组件,但是使用一遍下来,感觉有两种问题:
1: 通过文档翻阅,组件无法满足需求,例如搜索定位,拖动地图中心点标记不动
2: 组件库似乎还不完善,有时会出现无法加载地图
最终决定还是使用sdk进行原生的研发

开发流程

一、sdk引入

因为使用react,必不可少的使用组件库,包括引入sdk,这里因为不想影响其他页面,加上是ahooks的粉丝,我采用的是useExternal去动态注入js资源,这样子保证全局的js唯一性。

import { useExternal } from 'ahooks'

useExternal("//api.map.baidu.com/api?v=2.0&ak=你的密钥";

二、创建百度地图实例

在引入sdk之后,根据sdk文档我们需要创建一个地图实例。
注意我们所需要实现的需求:
1: 创建地图
2: 初始化地图能够根据当前位置进行定位并展示
3: 地图具备搜索
4: 标记位于中心不可移动,拖动地图获取标记经纬度

1:创建地图

创建地图需要注意,sdk的地图实例对象需要绑定对应id的div,且该div必须具备有宽度与高度,才能正确创建地图

 <div id="container"></div>
 const map = new BMapGL.Map('container'); // 创建Map实例
 map.centerAndZoom(new BMapGL.Point(116.404, 39.915), 18); // 初始化地图,设置中心点坐标和地图级别

注:此时最好将该map对象存起来,后续在地图上进行其他操作时可以更便捷

2:根据当前位置进行定位并展示中心点

此时我们需要将地图的中心点设置为我们当前的位置,在此就遇到许多坑了,先贴上官方的方案

  // 获取当前定位并且设置中心点
    const geolocation = new BMapGL.Geolocation();
    geolocation.enableSDKLocation()// 开启sdk辅助定位,适用于weiview
    geolocation.getCurrentPosition((r: any) => {
      // 设置当前城市用以搜索使用
      setCity(r.address.city)
      const { lat, lng } = r.point
      map.panTo({ lat, lng }, {})// 定位至中心点
      setCenterPoint({ lat, lng })

此时利用百度api的Geolocation对象,我们可以获取到当前位置的经纬度并且定位地图,但是在此会存在经纬度偏差较大的问题,后面上网查询大致原因,总结了一下
百度的定位方法会优先使用H5的navigator.geolocation.getCurrentPosition进行原生gps定位并且内部转化为百度坐标系。这里需要注意,百度使用的是百度坐标系,其他例如原生方法,高德地图等获取的是国测局坐标系,若使用原生则需要将gps坐标调用百度的Convertor方法转化为百度坐标才可在地图中展示正常,方法如下

 navigator.geolocation.getCurrentPosition((position) => {
      const lat = position?.coords?.latitude;
      const lng = position?.coords?.longitude;
      console.log({ position, lat, lng })
      const convertor = new BMap.Convertor();
      const pointArr = [];
      pointArr.push({ lat, lng });
      convertor.translate(pointArr, 1, 5, (data) => {
        const { pointArrData = [] } = data
        const point = {
          lat: pointArrData[0].lat,
          lng: pointArrData[0].lng
        }
      })
    }, (err) => console.log({ err }));

而原生的navigator.geolocation,谷歌已经对非https协议的网站禁用了该功能,因此开发环境的定位有时会使用ip定位,此时的经纬度就与当前所在位置产生偏差。这也就是为什么百度的定位方法会导致定位不准确的原因
解决方法网上说的是使用百度接口进行定位,但我自己掉了这些接口依旧是不准确的,个人觉得最优解便是试一试原生navigator.geolocatione 的经纬度转为百度坐标系

3: 地图具备搜索

这里选择最为简便的方式,百度似乎有提供接口进行信息的请求,这个后续可能回去做,而紧急需求只采用了最为简便易行的方式,但就是这种方式依旧遇到了坑,引用百度文档里的方法,将搜索对象与一个input框进行绑定,根据input里的值进行展示关联地址名称,通过Autocomplete对象绑定确认事件可以将地址列表的某一项点击做操作,例如展示到地图中心

   <div id="r-result">
        <input className={styles.inputCss} type="text" id="suggestId" size={24} placeholder='请输入查询地址' />
   </div>

   const ac = new BMap.Autocomplete(    // 建立一个自动完成的对象,suggestId为input的id,city是当前城市名称,也可以设置经纬度
      {
        "input": "suggestId",
        "location": city
      });

    ac.addEventListener("onconfirm", (e: any) => {    // 鼠标点击下拉列表后的事件
      const { value } = e.item;
      myMap.clearOverlays();
      const myValue = value.province + value.city + value.district + value.street + value.business;
      // 搜索调用
      const myFun = (resoult: any, local: any) => {
        const pp = local.getResults().getPoi(0).point;    // 获取第一个智能搜索的结果
        // 创建图标标记
        const marker = new BMapGL.Marker(pp, {
          enableDragging: true,
        });
        myMap.addOverlay(marker);
        setCenterPoint(pp)
        myMap.centerAndZoom(pp, 18);
      }
      const local = new BMap.LocalSearch(city)
      local.search(myValue, { forceLocal: true });
      local.setSearchCompleteCallback((i: any) => myFun(i, local));
    });

其实主要用到的是百度的LocalSearch对象进行搜索,但是这里会遇到一个问题,按照下面百度文档提供的方法,会存在无法取得搜索成功后点击对应地址的回调

var local = new BMap.LocalSearch(map, { //智能搜索
	onSearchComplete: myFun
    });

我发现这里的onSearchComplete会无法执行,但是将该代码放在html文件中是正常的,也就是百度文档的例子,不知道是不是sdk在react中执行报错
因此改用了下面的回调调用

local.setSearchCompleteCallback((i: any) => myFun(i, local));

这样就可以成功执行回调了

4: 标记位于中心不可移动,拖动地图获取标记经纬度

其实方案就是将一个img定位放在页面中心,获取经纬度则在map对象的拖动结束事件dragend中用百度map对象提供的map.getCenter()获取,实际操作误差不超过10m

页面耗时1d完成,主要都在解决定位不准确的问题,其实到现在也没有很明确的方案,似乎一切问题到了生产的https就可以解决,但因为还没上线
,还有待商榷

posted @ 2022-11-29 15:56  迷失哥哥  阅读(1259)  评论(0编辑  收藏  举报