iPhone 自带的指南针软件除了能显示方向外也能显示经纬度和海拔高度,如果有网络的话,还能显示中文位置信息,但是在 iOS 15 的一个版本更新中,苹果去除了经纬度和海拔高度,指南针只能显示方向和中文位置信息。国内的地图软件也只能显示中文的位置信息,不会显示经纬度坐标。

我有时候需要查看所在位置的经纬度和海拔高度,现在的浏览器都提供了位置信息相关的 API,在有 GPS 的移动设备上可以直接调用 GPS 来获取位置坐标。

下面简单写一下获取位置坐标和验证位置坐标的方法,访问 位置信息demo 可以直接查看经纬度和海拔高度,位置信息demo 只是一个静态页面,不会收集位置信息。

坐标简单说明

这里获取的只是经纬度坐标数值,如果需要在地图上显示位置的话,需要使用百度或高德的 API,

大多数 API 获取的坐标都是 GPS WGS-84 标准坐标,Google 地图和国外大多数地图使用的也是 WGS-84 坐标。

国内使用的是 GCJ-02 火星坐标,这个坐标相比 WGS-84 标准坐标来说,加入了偏移算法,也就是说如果你在 Google 地图上使用 GCJ-02 火星坐标,获取的位置也是偏移的。

有的手机在国内使用 API 获取的经纬度坐标也有可能是 GCJ-02 火星坐标。

百度地图和高德地图还有一套他们自己的坐标算法,他们的坐标在 GCJ-02 火星坐标 的基础上又加上了一套偏移算法。如果你需要调用他们的 API 在地图上 标注位置的话,还需要进行一次转换。

获取位置信息

下面获取位置信息,然后在控制台输出:

navigator.geolocation.getCurrentPosition(position => {
  // 在控制台输出经纬度和海拔高度
  console.log(`纬度:${position.coords.latitude}`);
  console.log(`经度:${position.coords.longitude}`);
  console.log(`海拔高度:${position.coords.altitude}`);
  console.log(`行进速度:${position.coords.speed}`);
  console.log(`行进方向:${position.coords.heading}`);
}, error => {
  // 在控制台输出错误信息
  console.log(error);
}, {
  enableHighAccuracy: true,
  timeout: 10000,
  maximumAge: 0
});

navigator.geolocation 接口可以用来获取和监听位置信息,其中 navigator.geolocation.getCurrentPosition 可以获取当前的位置信息。

navigator.geolocation.getCurrentPosition 可以传入三个参数:

  • success 回调函数会在成功时触发,回调函数可以传入一个 position 来接收位置信息
  • error 回调函数会在获取位置失败时触发,回调函数可以传入一个 error 来接收错误信息
  • position 对象是一个可选的选项

其中 position 选项可以包含:

  • enableHighAccuracy 高精度,可以传入 truefalse
  • timeout 超时,可以传入一个毫秒数字
  • maximumAge 最大位置缓存时间,可以传入一个毫秒数字,在缓存时间内会直接使用缓存的位置信息,不会获取最新的位置信息,不需要缓存可以设置为 0

成功的回调函数可以传入一个 position 来接收位置信息,position 包含:

  • coords 位置信息对象
  • timestamp 获取位置时的时间戳

其中 coords 位置信息对象又包含:

  • latitude 纬度坐标
  • longitude 经度坐标
  • altitude 海拔高度
  • speed 行进速度
  • heading 行进方向
  • accuracy 位置准确度
  • altitudeAccuracy 海拔准确度

在第一次调用 navigator.geolocation.getCurrentPosition 时,浏览器会弹出授权对话框,只有用户允许才能获取位置信息。

一些浏览器可能需要在 HTTPS 下才能获取位置信息,iPhone 的 Safari 就需要在 HTTPS 下才能获取位置信息,Google Chrome 使用本地的 HTML 文件就能获取位置信息。

验证位置信息

不同设备的定位方式不一样,获取的坐标精度也会不一样,甚至有的手机在国内可能获取的是 GCJ-02 火星坐标。

PC 端的浏览器使用的是 IP 定位,也就是说 PC 浏览器获取的是 IP 所在地区的经纬度,PC 也无法获取海拔高度信息。PC 上的 Google Chrome 浏览器在国内不开代理的情况下无法获取位置坐标,开启代理的情况下获取的是代理服务器 IP 的归属地坐标。Edge 浏览器可以获取 IP 归属地的坐标。

手机浏览器可以使用 GPS 来获取位置坐标,获取的位置精度要高一些,而且包含海拔高度。

在断网的情况下,手机也能获取位置坐标,PC 在断网的情况下无法获取位置坐标。

如果需要验证获取的位置坐标可以打开 Google 地图,把地图调整为卫星图,在搜索框输入 纬度,经度 ,例如 30.2595482,120.1457393 ,查看地图上显示的定位是否是所在位置。因为 Google 地图的中国大陆地图有偏移,查看位置的时候只需要看卫星图片,不需要看路网和名称。

Google地图定位到西湖断桥

上图的坐标会定位到西湖的断桥,但是 Google 地图的路网和名称都是偏移的,只有卫星图片不会偏移。

我测试的 iPhone 的 Safari 浏览器获取的是 GPS WGS-84 标准坐标。

监听位置变化

上面的 navigator.geolocation.getCurrentPosition 只能单次获取当前位置,虽然可以使用定时器多次调用,但是也无法获取行进速度和方向。

要监听位置变化可以使用 navigator.geolocation.watchPositiongeolocation.watchPosition 的参数还是和上面的 geolocation.getCurrentPosition 一样的,在成功的回调函数也可以传入一个 position 来接收位置信息。

下面在页面中放几个 h2 ,然后把 h2 的内容设置为实时位置:

const h2El = document.querySelectorAll('h2');  // h2标签

const watchPositionId = navigator.geolocation.watchPosition(position => {
  // 把 h2 的内容设置为获取的位置信息
  h2El[0].innerHTML = `纬度:${position.coords.latitude}`;
  h2El[1].innerHTML = `经度:${position.coords.longitude}`;
  h2El[2].innerHTML = `海拔高度:${position.coords.altitude}`;
  h2El[3].innerHTML = `行进速度:${position.coords.speed}`;
  h2El[4].innerHTML = `行进方向:${position.coords.heading}`;
}, error => {
  // 在控制台输出错误信息
  console.log(error);
}, {
  enableHighAccuracy: true,
  timeout: 10000,
  maximumAge: 0
});

geolocation.watchPosition 获取的位置信息和 geolocation.getCurrentPosition 是一样的,但是 geolocation.watchPosition 可以获取行进速度和方向。

这里的方向使用的是 0 到 359 度的数值,0 为正北、90 为正东、180 为正南、270 为正西。

监听位置变化只能使用带有 GPS 的手机,而且受限于 GPS 精度和环境,短距离的移动可能不会被监听到,有时候静止不动也可能会触发位置变化。

如果需要取消监听可以使用 navigator.geolocation.clearWatch ,需要传入一个 监听ID,在调用 geolocation.watchPosition 的时候会返回一个监听ID,我上面的 watchPositionId 就是用来存储返回的监听ID,在使用 geolocation.clearWatch 取消监听时可以直接传入监听ID。