地图定位问题

主要介绍了 HTML5 原生地图定位、百度地图定位的使用,也说明了 GPS 定位、ip 地址定位、基站定位、wifi 定位,分析了地图定位不准的原因

1. HTML5 原生地图定位

HTML5 原生地图定位通过geolocation实现,具体 API 使用可以查看官网:Geolocation API

用来获取设备当前位置:navigator.geolocation.getCurrentPosition(success, error, options)

js 复制代码
export function getLocalPosition() {
  return new Promise((resolved, rejected) => {
    // 检查浏览器是否支持地理位置功能
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        // 1. 成功的回调处理:
        (position) => {
          // 获取的gps位置(经纬度),需要转为地图对应坐标
          let lat = position.coords.latitude;
          let lng = position.coords.longitude;

          // 转为百度坐标
          const pointBak = new BMap.Point(lng, lat); // 使用经纬度创建百度地图的坐标点
          const convertor = new BMap.Convertor(); // 创建百度地图的坐标转换器
          convertor.translate([pointBak], 1, 5, (resPoint) => {
            if (
              resPoint &&
              resPoint.status === 0 &&
              resPoint.points &&
              resPoint.points.length
            ) {
              // 坐标转换成功,更新经度和纬度为转换后的坐标
              lng = resPoint.points[0].lng;
              lat = resPoint.points[0].lat;
              resolved(resPoint.points[0]);
            } else {
              rejected("坐标转化失败");
            }
          });
        },
        // 2. 失败的回调处理
        (err) => {
          let errMsg = "";
          switch (err.code) {
            case err.PERMISSION_DENIED:
              errMsg = "未开启获取位置信息的权限";
              break;
            case err.POSITION_UNAVAILABLE:
              errMsg = "获取位置信息出错";
              break;
            case err.TIMEOUT:
              errMsg = "获取位置信息超时";
              break;
            default:
              errMsg = "获取位置时发生未知错误";
              break;
          }
          rejected(errMsg);
        },
        // 3. 可选参数配置
        {
          timeout: 5000, // 超时时长
          enableHighAccuracy: true, // 设置为高精度定位
          maximumAge: 0, // 可接受返回的可能缓存位置的最大期限
        }
      );
    } else {
      rejected("当前浏览器不支持html5定位");
    }
  });
}

2. 百度地图定位

百度地图定位,具体可查看官网教程:JavaScript API v2.0 之定位

js 复制代码
export function getBaiduPosition() {
  return new Promise((resolved, rejected) => {
    // 获取地址文字信息
    const geolocation = new BMap.Geolocation();
    // 浏览器定位:优先调用浏览器H5定位接口,如果失败会调用IP定位
    geolocation.getCurrentPosition(
      (data) => {
        if (data) {
          resolved(data);
        } else {
          rejected("获取位置信息失败");
        }
      },
      { enableHighAccuracy: true }
    );
  });
}

3. 地图定位组件

使用的是@uiw/react-baidu-map,基于 React 封装的百度地图组件

ts 复制代码
import { Marker, Map, GeolocationControl, Circle } from "@uiw/react-baidu-map";
function map(props: iProps) {
  const [position, setPosition] = useState({ lng, lat })

  // 地图全部加载完毕
  function mapLoaded() {
    // 获取当前坐标
    getBaiduPosition()
      .then(points => {
        // 获取当前位置经纬度
        const lng = points.longitude || points.lng
        const lat = points.latitude || points.lat
        const point = new BMap.Point(lng, lat)
        // 获取当前位置
        const geo = new BMap.Geocoder()
        geo.getLocation(point, data => {
          // 获取详细地址信息
            const { address, surroundingPois } = data
            setAddress(address)
            const detail = surroundingPois[0]?.title || '' // 详细地址不存在 则置为空
            setAddressMesDetail(detail)
        })
      })
  }

  // 手动定位
  function locationManual(result: any) {
      const { point } = result
      // 设置地址坐标
      setPosition(point)
  }

  return (
    <>
      <Map
        zoom={15}
        center={position}
        onTilesLoaded={mapLoaded}
        enableDragging={false}
        enablePinchToZoom={false}
        enableScrollWheelZoom={false}
        enableMapClick={false}
        enableDoubleClickZoom={false}
      >
        <Marker icon={icon} animation={2} position={position} />
        <Circle
          radius={400}
          enableEditing={false}
          strokeOpacity={0.3}
          strokeWeight={1}
          strokeColor="#BBDEFF"
          fillColor="#BBDEFF"
          fillOpacity={0.5}
          center={position}
        />
        {previewInfo ? (
          <></>
        ) : (
          // 定位不准时,可以手动定位处理
          <GeolocationControl
            enableAutoLocation={true}
            offset={new BMap.Size(20, 70)}
            anchor={BMAP_ANCHOR_BOTTOM_RIGHT}
            onLocationSuccess={locationManual}
            onLocationError={(StatusCode) => {
              Toast.fail(`定位失败, ${StatusCode}`, 2);
            }}
          />
        )}
      </>
    </>
  );
}

export default map;

4. 定位分类

    1. GPS 定位:全球定位系统,通过卫星位置和设备距离计算设备位置
    • 优点:精度高
    • 缺点:在室内时,讯号会被阻挡,所以室内 GPS 定位不准
    1. ip 地址定位:根据联网设备的 ip,通过查到数据库,可以粗略地知道这个 ip 所在的地理位置。
    • 缺点:靠的是大量的信息收集,而不是直接确定用户当前位置
    1. 基站定位:基站是能进行信号交换的站点。基站位置是已知的,根据手机接收基站信号强度计算位置
    • 缺点:手机必须处于 SIM 卡注册状态下。受信号干扰和基站密度影响,精度较低
    1. wifi 定位:记录 WiFi 信号和设备位置,通过算法确定位置,解决室内定位问题
    • 缺点:当某个 WiFi 搬家后,数据库没有及时更新,就会出现定位不准的问题

5. 地图定位不准分析

浏览器定位实际上都是使用了 HTML5 的 Geolocation 功能,但不是那么好用,由于科学上网的限制,国内的手机"阉割"了谷歌 GMS 服务包,导致 HTML5 的 geolocation 无法使用 wifi 和基站定位服务,所以经常会定位失败。

当然,我们也可以用其他的厂商,如百度、高德、搜狗等,他们的策略是如下:

浏览器原生定位接口定位失败后,系统会调用 IP 定位,返回定位点所在城市中心点。此时,定位精度范围返回"null"。

最终解决方案是:配置好百度或高德的 SDK,使用 HTML5+API 的 geolocation.getCurrentPosition()利用原生定位获取到坐标点后,再用百度或高德的 JS API 去实现其他的地图模块功能。

相关推荐
zqx_72 分钟前
随记 前端框架React的初步认识
前端·react.js·前端框架
惜.己19 分钟前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
什么鬼昵称42 分钟前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色1 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2341 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河1 小时前
CSS总结
前端·css
NiNg_1_2341 小时前
Vue3 Pinia持久化存储
开发语言·javascript·ecmascript
读心悦1 小时前
如何在 Axios 中封装事件中心EventEmitter
javascript·http
BigYe程普2 小时前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
神之王楠2 小时前
如何通过js加载css和html
javascript·css·html