矢量数据源接入
数据源负责「把外部数据变成要素」,格式负责解析。两者分开配置, 换格式不用动图层,换图层也不用重写解析逻辑。
按格式选 source 与 format
| 数据 | format | 坐标处理 | 说明 |
|---|---|---|---|
| GeoJSON | ol.format.GeoJSON | 声明 dataProjection | 通用,属性结构直接可用 |
| TopoJSON | ol.format.TopoJSON | 同上 | 共享弧段,体积小 |
| KML | ol.format.KML | 固定经纬度,自动转换 | 可提取样式与文件夹结构 |
| GML | ol.format.GML2 / GML3 | 按 srsName | 需要声明 featureNS 与要素名 |
| GPX | ol.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)。