Skip to content

高德地图官方转坐标失败

最近开发自己结婚要用的网站,里面用到了高德地图,之前开发过类似的地图功能,所以信誓旦旦很快能搞定,但是在用高德 JS API 2.0 的官方定位插件进行定位时,发现有个问题,无论如何都会出现位置偏移。

之前开发过,我知道各家坐标系的问题,但是我这是高德自己定位自己用,没有第三方的坐标来源,怎么会出现偏移?

特别是我在配置插件的时候已经设置了转换为 true, 在开发环境就能定位准确,在部署生产后就一直有偏移。

ts
useEffect(() => {
  // 确保代码只在客户端执行
  if (typeof window === "undefined") return;
  if (!mapRef.current) return;
  // 确保只初始化一次地图
  if (map) return;
  let mapInstance: AMap.Map | null = null;

  // 设置安全密钥(如果有的话)
  if (process.env.NEXT_PUBLIC_AMAP_SECURITY_KEY) {
    (
      window as typeof window & {
        _AMapSecurityConfig?: { securityJsCode: string };
      }
    )._AMapSecurityConfig = {
      securityJsCode: process.env.NEXT_PUBLIC_AMAP_SECURITY_KEY,
    };
  } else {
    console.warn("SECURITY_KEY 加载失败");
  }

  // 动态加载高德地图
  const loadAMap = async () => {
    const AMapLoader = (await import("@amap/amap-jsapi-loader")).default;
    return AMapLoader.load({
      key: process.env.NEXT_PUBLIC_AMAP_KEY || "", // 使用环境变量中的API密钥
      version: "2.0",
      plugins: ["AMap.Scale", "AMap.ToolBar", "AMap.Geolocation"],
    });
  };

  loadAMap()
    .then((AMap) => {
      // 保存AMap对象以便后续使用
      setAMapInstance(AMap);

      // 创建地图实例
      const instance = new AMap.Map(mapRef.current, {
        zoom: 15,
        center: [111.1111, 222.2222], // 初始中心点,需要替换为实际坐标
        resizeEnable: true,
      });

      mapInstance = instance;

      // 添加比例尺控件
      instance.addControl(new AMap.Scale());

      // 添加工具条控件
      const toolbar = new AMap.ToolBar({
        position: "RT", // 设置工具栏在右上角
      });
      instance.addControl(toolbar);

      // 添加定位控件
      const geolocation = new AMap.Geolocation({
        enableHighAccuracy: true,
        timeout: 15000, // 增加超时时间
        maximumAge: 0, // 不使用浏览器原生定位的缓存时间,毫秒
        convert: true, // 是否将定位结果转换为高德坐标
        position: "RT", // 右上角
        offset: [15, 85], // 缩略图距离悬停位置的像素距离
        panToLocation: true, // 定位成功后是否自动移动到响应位置
        zoomToAccuracy: true, // 定位成功后是否自动调整级别
      });

      // 添加定位回调
      geolocation.on("complete", (data: AMap.Geolocation.GeolocationResult) => {
        console.log("定位成功", data);
      });

      geolocation.on("error", (error: AMap.Geolocation.ErrorStatus) => {
        console.error("定位失败", error);
      });

      instance.addControl(geolocation);

      setMap(instance);
    })
    .catch((e) => {
      console.error("地图加载失败", e);
    });

  // 清理函数
  return () => {
    if (mapInstance) {
      mapInstance.destroy();
    }
  };
}, []); // 只在组件挂载时初始化一次

于是尝试抓包,发现定位的结果如下:

js
// 打印: 定位成功 
{
  status: 0,
  code: 0,
  info: "SUCCESS",
  position: [111.1111, 222.222], // 这是脱敏的位置数据
  location_type: html5,
  message: "Get geolocation success.Convert failed.", // 这里提示转换失败
  accuracy: 75,
  isConverted: false,
  altitude: null,
  altitudeAccuracy: null,
  heading: null,
  speed: null,
  type: "complete"
 }

message:Get geolocation success.Convert failed.

这句话很可疑,因为我在配置插件的时候已经设置了转换为 true。

于是去提交了工单,高德的工程师反馈,这个转换错误,大概率是因为安全密钥没有挂载成功,往这个方向排查。结果我去看,生产果然没有配置这个变量,开发环境配置了所以能够精准定位。

于是赶紧去生产配置,重新部署,搞定。

补充知识 1: 高德地图的坐标转换 在中国,地图坐标系统比较特殊。主要有以下几种坐标系:

  1. WGS84 坐标系:国际标准坐标系,GPS 设备获取的原始坐标。
  2. GCJ-02 坐标系:国测局 02 年发布的坐标系统,也叫火星坐标系,是在 WGS84 基础上加密偏移后的坐标系。高德地图、腾讯地图、Google 中国地图使用此坐标系。
  3. BD-09 坐标系:百度坐标系,在 GCJ-02 基础上再次加密偏移后的坐标系。

高德地图的坐标转换主要涉及以下几种情况:

  • HTML5 Geolocation API 获取的坐标:这是 WGS84 坐标系,需要转换为 GCJ-02 才能在高德地图上准确显示。
  • 第三方设备获取的 GPS 坐标:同样是 WGS84 坐标系,需要转换。
  • 其他地图平台的坐标:如百度地图的 BD-09 坐标,需要先转换为 GCJ-02。

在高德地图 API 中,convert参数就是控制是否进行这种转换的关键。当设置convert: true时,API 会尝试将获取到的坐标转换为高德的 GCJ-02 坐标系。但这个转换需要安全密钥(Security Key)正确配置才能生效,否则会出现"Convert failed"的错误。

如果需要手动进行坐标转换,高德地图提供了坐标转换服务 API:

https://restapi.amap.com/v3/assistant/coordinate/convert

此外,也有一些开源的坐标转换工具库可以在前端直接使用,如 coordtransform、gcoord 等。

补充知识 2:Convert failed

高德的工程师反馈,这个报错基本就是因为安全密钥未配置或者配置错误导致的,如果看到这个报错,请着重往这个方向排查。

非商业用途,允许转载,需注明出处