矢量图层与样式
矢量部分是 OpenLayers 相对轻量地图库的主要优势: 几何体、要素、数据源、图层四层分离,样式可以是常量,也可以随缩放级别和属性动态计算。
四层结构
| 层级 | 类 | 作用 |
|---|---|---|
| 图层 | ol.layer.Vector | 控制可见性、透明度、叠放顺序 |
| 数据源 | ol.source.Vector | 持有要素集合,负责增删和范围计算 |
| 要素 | ol.Feature | 几何体加属性,一条业务记录 |
| 几何 | ol.geom.Point 等 | 实际坐标,决定画在哪 |
要素上的属性用 get / set 读写,没有固定表结构:
var feature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([116.404, 39.915])),
name: '王府井',
level: 'high'
});
feature.get('name'); // '王府井'
feature.set('level', 'low');
三种设置样式的方式
第一种,给要素单独设置,适合少量重点要素:
feature.setStyle(new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({ color: '#1f5fd0' }),
stroke: new ol.style.Stroke({ color: '#fff', width: 2 })
})
}));
第二种,给图层设置样式函数,适合按属性分类。函数返回数组时同一个要素可以叠加多层符号:
var styleFunction = function (feature, resolution) {
var isKey = feature.get('level') === 'high';
return [
new ol.style.Style({
image: new ol.style.Circle({
radius: isKey ? 8 : 5,
fill: new ol.style.Fill({ color: isKey ? '#d0453a' : '#1f5fd0' })
})
}),
new ol.style.Style({
text: new ol.style.Text({
text: feature.get('name'),
offsetY: -16,
font: '500 12px sans-serif',
fill: new ol.style.Fill({ color: '#16181d' }),
stroke: new ol.style.Stroke({ color: '#fff', width: 3 })
})
})
];
};
var layer = new ol.layer.Vector({
source: source,
style: styleFunction
});
第三种,在 ol.source.Vector 上设置,对该数据源派生的所有图层生效。
用得多的是前两种,第三种适合多个图层共用一套符号。
性能提醒:样式函数在每次重绘、每个要素上都会被调用,
里面不要做 DOM 操作或网络请求。需要缓存时按属性值预先建好
ol.style.Style 对象,函数里只做查表。
按分辨率分级显示
样式函数的第二个参数是当前分辨率,用它控制“放大后才显示标注”这类规则:
var labelStyle = new ol.style.Style({
text: new ol.style.Text({ text: '标注', font: '12px sans-serif' })
});
var styleFunction = function (feature, resolution) {
var base = new ol.style.Style({
image: new ol.style.Circle({ radius: 5, fill: new ol.style.Fill({ color: '#1f5fd0' }) })
});
// 分辨率小于 20 米/像素,大约相当于 14 级以上
return resolution < 20 ? [base, labelStyle] : base;
};
几何类型
| 类 | 坐标结构 | 样式字段 |
|---|---|---|
ol.geom.Point | [x, y] | image |
ol.geom.LineString | [[x, y], ...] | stroke |
ol.geom.Polygon | [[[x, y], ...]] | fill + stroke |
ol.geom.MultiPolygon | 多一层数组 | 同上 |
多边形注意外环和内环的区别:外环按逆时针给出, 内环(洞)按顺时针,数组第一个是外环。
var polygon = new ol.geom.Polygon([[
ol.proj.fromLonLat([116.35, 39.93]),
ol.proj.fromLonLat([116.45, 39.93]),
ol.proj.fromLonLat([116.45, 39.88]),
ol.proj.fromLonLat([116.35, 39.88]),
ol.proj.fromLonLat([116.35, 39.93])
]]);
修改样式后为什么没变化
用 feature.setStyle() 改单个要素会立即重绘。
但如果样式来自函数或图层,属性变了不会自动触发重绘,
需要显式通知图层:
feature.set('level', 'high'); // 属性已改,画面未变
layer.changed(); // 触发重新应用样式函数
批量新增要素时用 source.addFeatures(features) 一次加入,
比循环 addFeature 少很多次重绘。
文字标注的常见处理
- 给
ol.style.Text配白色描边,深色底图上才看得清。 - 标注互相压盖时,图层开启
declutter: true,由渲染器自动避让。 overflow: true允许文字超出几何体范围,点位密集时更整齐。- 标注内容为空字符串时整个 text 样式不渲染,可以用它做条件开关。
var layer = new ol.layer.Vector({
source: source,
declutter: true,
style: styleFunction
});
要素数量很大时(超过几千个点),普通矢量图层会明显卡顿。
可换成 ol.layer.Heatmap、ol.source.Cluster 聚合,
或改用 WebGL 渲染的 ol.layer.WebGLPoints。
经纬志(2026)。《矢量图层与样式》。https://www.jingweizhi.com/openlayers/tutorial/vector-style.html(访问日期 2026-11-03)。