经纬志
首页 / 实战手册 / 坐标与投影

两个图层各用一套坐标系,叠上去错开半屏

先看结论

底图正常显示,叠加的规划图却整体偏右上,缩放越大偏得越多。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

View 设为 EPSG:3857,底图用 OSM 正常。 叠加的第一个图层是 GeoJSON,坐标是经纬度,L.geoJSON 那套写法搬过来后直接可用; 第二个图层是 ImageStatic 配一张覆盖 116.0°E ~ 116.6°E、39.7°N ~ 40.1°N 的规划图 PNG, 用 extent: [116.0, 39.7, 116.6, 40.1] 添加。

结果规划图缩小并贴在左上角,与底图错开大半个屏幕。 把 extent 改成米值 [12913000, 4820000, 12980000, 4865000] 后图变大但仍偏, 而且在北纬 40° 附近纵向被压扁。

原因

OpenLayers 的所有图层都必须声明自己的数据坐标系 projection。 不声明时,ImageStatic 默认使用 View 的投影(这里是 3857), 于是 extent 里的 116.0 被当作 116 米,整张图缩成 0.6 米宽,贴在原点附近。

改成米值后地图位置对了,但 ImageStatic 是直接把图片拉伸铺满 extent, 不做逐像素重投影,所以在 3857 下按经纬度矩形铺图会纵向压扁约 1.3 倍。

排查过程

  1. 打印每个图层的 layer.getSource().getProjection().getCode()。
  2. 与 map.getView().getProjection().getCode() 比对,不一致又没有声明重投影,就会错位。
  3. 看 extent 数值量级:十位以内是度,七位以上是米。
  4. 把 extent 用 ol.proj.transformExtent 转成 View 投影后再加,看是否对齐。
console.log(view.getProjection().getCode());            // EPSG:3857
console.log(imgLayer.getSource().getProjection().getCode()); // EPSG:3857(默认)
console.log(extent);   // [116, 39.7, 116.6, 40.1] 单位是度,与 3857 不匹配

解决方案

数据是什么坐标系就声明什么,让 OpenLayers 负责重投影; 对不做重投影的 ImageStatic,先把 extent 转到 View 投影。

import { transformExtent } from 'ol/proj';

// 1. 让 ImageStatic 声明自己打哪儿来
new ImageLayer({
  source: new ImageStatic({
    url: '/data/plan.png',
    projection: 'EPSG:4326',                       // 关键
    imageExtent: [116.0, 39.7, 116.6, 40.1]
  })
});

// 2. 或者直接把 extent 转成 View 的投影(推荐,裁剪更准)
const ext3857 = transformExtent([116.0, 39.7, 116.6, 40.1], 'EPSG:4326', 'EPSG:3857');
new ImageLayer({
  source: new ImageStatic({
    url: '/data/plan.png',
    projection: 'EPSG:3857',
    imageExtent: ext3857
  })
});

// 3. 矢量图层同理
new VectorLayer({
  source: new VectorSource({
    url: '/data/roads.geojson',
    format: new GeoJSON({ dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' })
  })
});

验证

规划图四角应与底图上对应的道路交叉口重合,误差小于 1 个像素; 在 10、12、14 三个缩放级别分别检查,偏差不应随级别放大。

const ext = transformExtent([116.0, 39.7, 116.6, 40.1], 'EPSG:4326', 'EPSG:3857');
console.log(ext.map(v => v.toFixed(0)));
// 约 [12912986, 4818065, 12979685, 4865202]

适用版本

库版本说明
OpenLayers7.x ~ 9.x图层 projection 未声明时继承 View 投影
ol/proj同版本transformExtent 支持 4326/3857 免注册
Leaflet1.xL.imageOverlay 的 bounds 必须是 LatLng,无需转换
引用本文

经纬志(2026)。《两个图层各用一套坐标系,叠上去错开半屏》。https://www.jingweizhi.com/cookbook/overlay-two-crs.html(访问日期 2026-11-03)。