OpenLayers 加载高德瓦片地图与百度坐标转换实战(05)
2026/8/22 20:16:20 网站建设 项目流程

OpenLayers加载高德瓦片+百度坐标:我花了两天才搞明白的坐标转换坑

公司项目里存的都是百度坐标(BD09),但领导偏偏要用高德瓦片做底图。我一开始以为直接gcoord.transform转一下就行,结果地图上一放,坐标偏了500多米。这篇文章把我在实际项目中踩的坑和最终的解决方案都记录下来,希望后来人少走弯路。


先说结论

百度坐标(BD09)要在高德瓦片上正确显示,必须分两步转换

BD09 → GCJ02 → EPSG:3857

而且第二步不能用gcoord.transform必须手写墨卡托投影公式,否则会偏。


一、为什么直接转不行?

1.1 我踩的第一个坑

一开始我这样写:

// 我以为这样就行...constcenter=gcoord.transform([116.404,39.915],gcoord.BD09,gcoord.EPSG3857)

结果放上去,红点离目标位置偏了好几百米。

1.2 查了三天才发现的原因

翻遍了gcoord的源码,发现:

// gcoord源码里 WebMercator = EPSG3857e.WebMercator="EPSG3857"

gcoord.WebMercatorgcoord.EPSG3857是同一个值!所以不管你写哪个,效果一样。

真正的问题是:gcoordBD09 → EPSG:3857直接转换跳过了GCJ02中间态,导致坐标偏移。

1.3 正确的转换链路

BD09(百度经纬度) → GCJ02(高德经纬度) ← gcoord可以做 → EPSG:3857(墨卡托) ← 必须手写

二、手写墨卡托投影公式

第二步转换我用了手写公式,这是EPSG:3857的标准定义:

/** * GCJ02经纬度 → WebMercator(EPSG:3857) * 公式:x = R * λ, y = R * ln(tan(π/4 + φ/2)) */constgcj02ToMercator=(coord)=>{constR=6378137// 地球半径(米)constlng=coord[0]*Math.PI/180constlat=coord[1]*Math.PI/180constx=R*lngconsty=R*Math.log(Math.tan(Math.PI/4+lat/2))return[x,y]}

然后组合成完整函数:

// BD09 → GCJ02constbd09ToGcj02=(coord)=>gcoord.transform(coord,gcoord.BD09,gcoord.GCJ02)// 完整链路:BD09 → GCJ02 → EPSG:3857constbd09ToMercator=(coord)=>gcj02ToMercator(bd09ToGcj02(coord))

和gcoord对比的结果

转换方式坐标结果与真实位置偏差
gcoord.BD09 → gcoord.EPSG3857约500米
gcoord.BD09 → gcoord.GCJ02+ 手写公式< 1米

三、高德瓦片加载

高德瓦片用标准XYZ格式,直接用ol/source/XYZ就行,比百度瓦片简单得多:

importXYZfrom'ol/source/XYZ'newTileLayer({source:newXYZ({url:'http://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',tileSize:256,crossOrigin:'anonymous'})})

和百度瓦片的区别

高德瓦片百度瓦片
数据源ol/source/XYZ直接用需要封装createBDXYZSource
瓦片编号标准XYZY轴反转,负数用"M"前缀
配置复杂度

四、完整Vue3组件

<template> <div class="wh100" ref="olMapRef"></div> </template> <script setup> import {ref, onMounted} from 'vue' import Map from 'ol/Map' import View from 'ol/View' import TileLayer from 'ol/layer/Tile' import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; import {GeoJSON} from "ol/format"; import gcoord from 'gcoord' import {Circle as CircleStyle, Fill, Stroke, Style} from "ol/style"; import XYZ from "ol/source/XYZ"; // ====== 坐标转换 ====== const bd09ToGcj02 = (coord) => gcoord.transform(coord, gcoord.BD09, gcoord.GCJ02) const gcj02ToMercator = (coord) => { const R = 6378137 const lng = coord[0] * Math.PI / 180 const lat = coord[1] * Math.PI / 180 const x = R * lng const y = R * Math.log(Math.tan(Math.PI / 4 + lat / 2)) return [x, y] } const bd09ToMercator = (coord) => gcj02ToMercator(bd09ToGcj02(coord)) const olMapRef = ref(null) onMounted(() => { // BD09坐标 → 墨卡托 const center = bd09ToMercator([116.404, 39.915]) const map = new Map({ target: olMapRef.value, layers: [ new TileLayer({ source: new XYZ({ url: 'http://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', tileSize: 256, crossOrigin: "anonymous" }) }) ], view: new View({ center: center, zoom: 10, projection: 'EPSG:3857' }) }) // 添加点验证坐标是否准确 let geoJsonData = { "type": "FeatureCollection", "features": [{ "type": "Feature", "id": 1, "properties": { "name": '', "level": 10, "zIndex": 200 }, "geometry": { "type": 'Point', "coordinates": center } }] } const layer = new VectorLayer({ source: new VectorSource({ features: new GeoJSON({}).readFeatures(geoJsonData) }) }) layer.setStyle(new Style({ image: new CircleStyle({ radius: 5, fill: new Fill({ color: '#ff0000' }), stroke: new Stroke({ color: '#ff0000', width: 3 }) }), })) map.addLayer(layer) }) </script>

五、踩坑记录

坑1:坐标偏移500米

原因gcoordBD09 → EPSG:3857跳过了GCJ02中间态。

解决:显式分两步,第二步手写公式。

坑2:gcoord.WebMercator和EPSG3857一样

改了gcoord.EPSG3857gcoord.WebMercator,发现没任何变化,因为它们值相同。

坑3:手写公式精度问题

手写公式用的是球体近似,和OpenLayers内置的fromLonLat有几米偏差。在瓦片地图场景下完全可以接受,如果需要更高精度可以用:

import{fromLonLat}from'ol/proj'constcenter=fromLonLat([116.404,39.915])// 更精确

六、总结

场景转换方式
BD09 + 高德瓦片BD09 → GCJ02+手写GCJ02 → EPSG:3857
BD09 + 百度瓦片BD09 → BD09MC(gcoord直接转)
BD09 + 天地图BD09 → EPSG:4326 → EPSG:3857

百度原始坐标位置

openlayers+高德瓦片包

更新日期:2026年8月
调试版本:OpenLayers 10.9.0

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询