三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

OpenLayers加载高德瓦片与GCJ02坐标转换实战(08)

OpenLayers加载高德瓦片与GCJ02坐标转换实战(08)

OpenLayers加载高德瓦片+高德坐标:最简单的地图集成方案

如果你的数据来自高德地图API,底图也用高德瓦片,那恭喜你——这是所有地图集成方案里最简单的一种。坐标不用偏移、瓦片不用封装,只需要做一次投影转换。这篇文章把完整实现和正反转换公式都整理清楚了。


先说结论

高德坐标(GCJ02)+ 高德瓦片,只需要一步转换:

GCJ02经纬度 → EPSG:3857墨卡托

手写公式10行搞定,不需要任何第三方库。


一、为什么这是最简单的场景?

要素坐标系说明
数据GCJ02高德API返回的坐标
底图GCJ02高德瓦片
OpenLayersEPSG:3857需要投影转换

数据和底图都是GCJ02,不需要处理坐标偏移,只做一次投影。

对比其他方案:

场景转换步骤复杂度
高德+高德1步简单
百度+高德2步+手写中等
百度+百度1步中等(瓦片特殊)
百度+天地图2步简单

二、正反转换公式

正向:GCJ02 → EPSG:3857

constgcj02ToMercator=(coord)=>{constR=6378137constlng=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]}

反向:EPSG:3857 → GCJ02

点击地图获取坐标时用:

constmercatorToGCJ02=(coord)=>{constR=6378137constx=coord[0]consty=coord[1]constlng=(x/R)*180/Math.PIconstlat=(2*Math.atan(Math.exp(y/R))-Math.PI/2)*180/Math.PIreturn[lng,lat]}

验证

constoriginal=[116.411299,39.908054]constmercator=gcj02ToMercator(original)constback=mercatorToGCJ02(mercator)console.log(original[0].toFixed(6)===back[0].toFixed(6))// trueconsole.log(original[1].toFixed(6)===back[1].toFixed(6))// true

精度说明

手写公式是球体墨卡托,和OpenLayers内置的fromLonLat(椭球体)有几米偏差。北京地区约3-5米,瓦片地图场景完全够用。


三、完整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 {Circle as CircleStyle, Fill, Stroke, Style} from "ol/style"; import XYZ from "ol/source/XYZ"; // GCJ02经纬度 → WebMercator(EPSG:3857) 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] } // WebMercator(EPSG:3857) → GCJ02经纬度 const mercatorToGCJ02 = (coord) => { const R = 6378137 const x = coord[0] const y = coord[1] const lng = (x / R) * 180 / Math.PI const lat = (2 * Math.atan(Math.exp(y / R)) - Math.PI / 2) * 180 / Math.PI return [lng, lat] } const olMapRef = ref(null) onMounted(() => { const center = gcj02ToMercator([116.411299, 39.908054]) 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>

四、点击获取高德坐标

在实际项目中,经常需要点击地图获取高德坐标用于业务:

map.on('click',(e)=>{// e.coordinate 是 EPSG:3857 墨卡托坐标constgcj02=mercatorToGCJ02(e.coordinate)console.log(`高德坐标:经度${gcj02[0].toFixed(6)}, 纬度${gcj02[1].toFixed(6)}`)})

五、全场景转换速查表

源坐标底图转换方式
GCJ02高德gcj02ToMercator(1步)
BD09高德BD09 → GCJ02+gcj02ToMercator(2步)
BD09百度BD09 → BD09MC(gcoord直接转)
BD09天地图BD09 → EPSG:4326 → EPSG:3857



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

← 返回列表