OpenLayers加载高德瓦片+高德坐标:最简单的地图集成方案
如果你的数据来自高德地图API,底图也用高德瓦片,那恭喜你——这是所有地图集成方案里最简单的一种。坐标不用偏移、瓦片不用封装,只需要做一次投影转换。这篇文章把完整实现和正反转换公式都整理清楚了。
先说结论
高德坐标(GCJ02)+ 高德瓦片,只需要一步转换:
GCJ02经纬度 → EPSG:3857墨卡托手写公式10行搞定,不需要任何第三方库。
一、为什么这是最简单的场景?
| 要素 | 坐标系 | 说明 |
|---|---|---|
| 数据 | GCJ02 | 高德API返回的坐标 |
| 底图 | GCJ02 | 高德瓦片 |
| OpenLayers | EPSG: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