经纬志
首页 / OpenLayers / 教程

矢量数据源接入

先看结论

数据源负责「把外部数据变成要素」,格式负责解析。两者分开配置, 换格式不用动图层,换图层也不用重写解析逻辑。

最后验证 2026-11-03 · OpenLayers 10.3.1 · 难度:入门 · 核验 2026-10-29 · 引用本文

按格式选 source 与 format

数据format坐标处理说明
GeoJSONol.format.GeoJSON声明 dataProjection通用,属性结构直接可用
TopoJSONol.format.TopoJSON同上共享弧段,体积小
KMLol.format.KML固定经纬度,自动转换可提取样式与文件夹结构
GMLol.format.GML2 / GML3按 srsName需要声明 featureNS 与要素名
GPXol.format.GPX固定经纬度轨迹、航点
矢量瓦片ol.format.MVT瓦片坐标系配 ol.source.VectorTile

GeoJSON 的正确配置

默认视图是 EPSG:3857,而 GeoJSON 里的坐标几乎总是经纬度。 不声明 dataProjection 时,OpenLayers 会把经纬度当成米, 要素跑到坐标原点附近。

var view = new ol.View({
  center: ol.proj.fromLonLat([116.397, 39.908]),
  zoom: 11
});

var source = new ol.source.Vector({
  url: '/data/districts.geojson',
  format: new ol.format.GeoJSON({
    dataProjection: 'EPSG:4326',
    featureProjection: view.getProjection()
  })
});

var layer = new ol.layer.Vector({
  source: source,
  style: new ol.style.Style({
    stroke: new ol.style.Stroke({ color: '#1f5fd0', width: 1.5 }),
    fill: new ol.style.Fill({ color: 'rgba(31, 95, 208, 0.15)' })
  })
});

map.addLayer(layer);

dataProjection 描述文件里的坐标,featureProjection 描述目标坐标。视图换成别的投影时,只改后者,数据文件不用动。

属性里的坐标不算数。GeoJSON 几何使用 [经度, 纬度] 顺序, 而属性表里可能写着「纬度, 经度」。手工拼接要素时这个顺序错一次, 整份数据都会跑到南半球。

KML 与 TopoJSON

KML 常用于业务方直接提供的点位与范围。它固定使用经纬度, 不需要额外声明数据投影,但样式解析要显式开启。

// KML:提取样式,忽略其中的图标尺寸
var kmlSource = new ol.source.Vector({
  url: '/data/facilities.kml',
  format: new ol.format.KML({
    extractStyles: true,
    extractAttributes: true
  })
});

// TopoJSON:需要声明数据投影
var topoSource = new ol.source.Vector({
  url: '/data/province.topo.json',
  format: new ol.format.TopoJSON({
    dataProjection: 'EPSG:4326',
    featureProjection: 'EPSG:3857'
  })
});

KML 里的图标路径是相对 KML 文件位置的,文件被移动后图标会 404。 需要统一符号时把 extractStyles 设为 false, 改用图层样式函数。

按视野范围加载

数据量大时不要一次拉全量。给数据源配 strategy, 并让服务端支持按 bbox 查询,每次只取当前视野内的要素。

var parcels = new ol.source.Vector({
  format: new ol.format.GeoJSON({
    dataProjection: 'EPSG:4326',
    featureProjection: 'EPSG:3857'
  }),
  strategy: ol.loadingstrategy.bbox,
  loader: function (extent, resolution, projection, success, failure) {
    var url = '/api/parcels?bbox=' + extent.join(',') + '&limit=2000';

    fetch(url)
      .then(function (res) {
        if (!res.ok) throw new Error('HTTP ' + res.status);
        return res.json();
      })
      .then(function (json) {
        var features = this.getFormat().readFeatures(json, {
          dataProjection: 'EPSG:4326',
          featureProjection: projection
        });
        this.addFeatures(features);
        success(features);
      }.bind(this))
      .catch(failure);
  }
});

loader 里必须调用 success 或 failure, 否则数据源会一直处于加载状态,后续的 change 事件不会触发。 已加载的要素默认不会因为视野移出而删除,需要清理时调用 source.clear()。

注意事项

  • 跨域读取需要服务端返回 Access-Control-Allow-Origin,本地文件直接打开时 fetch 会失败。
  • GeoJSON 的 id 字段会映射成要素 id,重复 id 会让选择和修改出现串号。
  • ol.format.GeoJSON 默认只读 Feature 与 FeatureCollection,单独的几何对象要包一层。
  • 服务端返回的坐标系是 CGCS2000 时,按 EPSG:4490 声明,不要当成 4326。
  • 数据源加载失败不会抛出到控制台以外的地方,接 source.on('featuresloaderror') 做提示。
引用本文

经纬志(2026)。《矢量数据源接入》。https://www.jingweizhi.com/openlayers/tutorial/data-sources.html(访问日期 2026-11-03)。