第03章 - 核心概念与架构设计
第03章 - 核心概念与架构设计
3.1 OpenLayers 设计理念
3.1.1 面向对象设计
OpenLayers 采用经典的面向对象设计模式,所有核心类都继承自基类,形成清晰的类层次结构:
┌─────────────────────────────────────────────────────────────┐
│ OpenLayers 类继承体系 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Disposable (可释放) │
│ │ │
│ └── Observable (可观察) │
│ │ │
│ └── BaseObject (基础对象) │
│ │ │
│ ├── Map │
│ │ │
│ ├── View │
│ │ │
│ ├── Layer (图层基类) │
│ │ ├── TileLayer │
│ │ ├── VectorLayer │
│ │ ├── ImageLayer │
│ │ └── VectorTileLayer │
│ │ │
│ ├── Source (数据源基类) │
│ │ ├── TileSource │
│ │ ├── VectorSource │
│ │ └── ImageSource │
│ │ │
│ ├── Feature │
│ │ │
│ ├── Interaction (交互基类) │
│ │ ├── DragPan │
│ │ ├── Draw │
│ │ └── Select │
│ │ │
│ └── Control (控件基类) │
│ ├── Zoom │
│ ├── ScaleLine │
│ └── Attribution │
│ │
└─────────────────────────────────────────────────────────────┘
3.1.2 可观察模式(Observable Pattern)
OpenLayers 的核心是可观察模式,所有对象都可以监听和触发事件:
import Observable from 'ol/Observable';
// Observable 类提供的基础能力
class MyClass extends Observable {
constructor() {
super();
this.value = 0;
}
setValue(newValue) {
const oldValue = this.value;
this.value = newValue;
// 触发自定义事件
this.dispatchEvent({
type: 'change:value',
oldValue: oldValue,
newValue: newValue
});
}
}
// 使用示例
const obj = new MyClass();
// 监听事件
obj.on('change:value', (event) => {
console.log(`值从 ${event.oldValue} 变为 ${event.newValue}`);
});
// 触发事件
obj.setValue(100);
3.1.3 属性系统(Properties)
BaseObject 提供了属性管理系统:
import BaseObject from 'ol/Object';
// 创建可观察对象
const obj = new BaseObject({
name: 'MyObject',
visible: true,
opacity: 1.0
});
// 获取属性
console.log(obj.get('name')); // 'MyObject'
// 设置属性
obj.set('opacity', 0.5);
// 获取所有属性
console.log(obj.getProperties()); // { name: 'MyObject', visible: true, opacity: 0.5 }
// 监听属性变化
obj.on('change:opacity', (event) => {
console.log('透明度已更改:', obj.get('opacity'));
});
// 批量设置属性
obj.setProperties({
name: 'NewName',
visible: false
});
3.1.4 资源释放机制
OpenLayers 对象实现了 Disposable 接口,确保资源正确释放:
import Map from 'ol/Map';
import { unByKey } from 'ol/Observable';
// 创建地图
const map = new Map({
target: 'map',
// ...
});
// 添加事件监听,保存 key
const key = map.on('click', (event) => {
console.log('点击');
});
// 移除单个事件监听
unByKey(key);
// 或使用 un 方法
const clickHandler = (event) => {
console.log('点击');
};
map.on('click', clickHandler);
map.un('click', clickHandler);
// 销毁地图时释放所有资源
map.dispose();
// 或者设置 target 为 null
map.setTarget(null);
3.2 核心对象模型
3.2.1 Map 对象
Map 是 OpenLayers 的核心对象,负责管理所有地图组件:
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import { defaults as defaultControls } from 'ol/control';
import { defaults as defaultInteractions } from 'ol/interaction';
const map = new Map({
// 挂载目标 DOM 元素
target: 'map',
// 图层集合
layers: [
new TileLayer({
source: new OSM()
})
],
// 视图配置
view: new View({
center: [0, 0],
zoom: 2
}),
// 控件(可选,有默认值)
controls: defaultControls({
attribution: true,
zoom: true,
rotate: false
}),
// 交互(可选,有默认值)
interactions: defaultInteractions({
doubleClickZoom: true,
dragPan: true,
mouseWheelZoom: true
}),
// 覆盖物集合
overlays: [],
// 其他配置
pixelRatio: window.devicePixelRatio,
moveTolerance: 1,
maxTilesLoading: 16
});
Map 常用方法:
// 图层管理
map.addLayer(layer);
map.removeLayer(layer);
map.getLayers(); // 返回 Collection
// 控件管理
map.addControl(control);
map.removeControl(control);
map.getControls();
// 交互管理
map.addInteraction(interaction);
map.removeInteraction(interaction);
map.getInteractions();
// 覆盖物管理
map.addOverlay(overlay);
map.removeOverlay(overlay);
map.getOverlays();
// 视图操作
map.getView();
map.setView(view);
// 坐标查询
map.getCoordinateFromPixel([x, y]);
map.getPixelFromCoordinate(coordinate);
map.getFeaturesAtPixel([x, y]);
// 渲染控制
map.render();
map.renderSync();
map.getSize();
map.updateSize();
// 目标元素
map.getTarget();
map.getTargetElement();
map.setTarget(element);
3.2.2 View 对象
View 管理地图的视图状态(中心点、缩放、旋转等):
import View from 'ol/View';
import { fromLonLat, toLonLat } from 'ol/proj';
const view = new View({
// 中心点(Web Mercator 坐标)
center: fromLonLat([116.4074, 39.9042]),
// 缩放级别
zoom: 10,
// 或使用分辨率代替缩放
// resolution: 1000,
// 旋转角度(弧度)
rotation: 0,
// 投影
projection: 'EPSG:3857',
// 缩放限制
minZoom: 2,
maxZoom: 18,
// 分辨率限制
// minResolution: 0.5,
// maxResolution: 10000,
// 范围限制
extent: undefined, // 或 [minX, minY, maxX, maxY]
// 约束设置
constrainRotation: true, // 旋转约束
enableRotation: true, // 允许旋转
constrainOnlyCenter: false, // 仅约束中心点
smoothExtentConstraint: true,
smoothResolutionConstraint: true,
// 缩放因子
zoomFactor: 2,
// 多分辨率支持
multiWorld: false,
// 显示边距
padding: [0, 0, 0, 0] // [top, right, bottom, left]
});
// 设置到地图
map.setView(view);
View 常用方法:
// 获取当前状态
view.getCenter(); // 获取中心点
view.getZoom(); // 获取缩放级别
view.getResolution(); // 获取分辨率
view.getRotation(); // 获取旋转角度
view.getProjection(); // 获取投影
// 设置状态
view.setCenter(center);
view.setZoom(zoom);
view.setResolution(resolution);
view.setRotation(rotation);
// 动画操作
view.animate({
center: fromLonLat([121.4737, 31.2304]),
zoom: 12,
duration: 1000,
easing: easeOut
});
// 适应范围
view.fit(extent, {
size: map.getSize(),
padding: [50, 50, 50, 50],
duration: 500
});
// 适应几何
view.fit(geometry, {
padding: [50, 50, 50, 50]
});
// 计算范围
view.calculateExtent(map.getSize());
// 约束检查
view.constrainCenter(center);
view.constrainResolution(resolution);
view.constrainRotation(rotation);
// 缩放操作
view.getZoomForResolution(resolution);
view.getResolutionForZoom(zoom);
view.getResolutionForExtent(extent, size);
3.2.3 Layer 对象
Layer 是图层的抽象基类,定义了所有图层的共同行为:
import TileLayer from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';
import ImageLayer from 'ol/layer/Image';
import LayerGroup from 'ol/layer/Group';
// 瓦片图层
const tileLayer = new TileLayer({
// 通用属性
visible: true, // 可见性
opacity: 1.0, // 透明度 (0-1)
zIndex: 0, // 堆叠顺序
extent: undefined, // 渲染范围
minZoom: undefined, // 最小缩放级别
maxZoom: undefined, // 最大缩放级别
minResolution: undefined,// 最小分辨率
maxResolution: undefined,// 最大分辨率
className: 'ol-layer', // CSS 类名
// 数据源
source: new OSM(),
// 预加载
preload: 0,
// 使用临时画布
useInterimTilesOnError: true,
// 自定义属性
properties: {
name: 'OSM底图',
type: 'basemap'
}
});
// 矢量图层
const vectorLayer = new VectorLayer({
source: vectorSource,
style: styleFunction,
// 矢量图层特有属性
declutter: false, // 去重叠
renderBuffer: 100, // 渲染缓冲区
updateWhileAnimating: false, // 动画时更新
updateWhileInteracting: false // 交互时更新
});
// 图层组
const layerGroup = new LayerGroup({
layers: [tileLayer, vectorLayer],
visible: true,
opacity: 1.0
});
Layer 常用方法:
// 可见性
layer.getVisible();
layer.setVisible(true);
// 透明度
layer.getOpacity();
layer.setOpacity(0.8);
// 堆叠顺序
layer.getZIndex();
layer.setZIndex(10);
// 范围
layer.getExtent();
layer.setExtent(extent);
// 分辨率约束
layer.getMinResolution();
layer.getMaxResolution();
layer.setMinResolution(resolution);
layer.setMaxResolution(resolution);
// 缩放约束
layer.getMinZoom();
layer.getMaxZoom();
layer.setMinZoom(zoom);
layer.setMaxZoom(zoom);
// 数据源
layer.getSource();
layer.setSource(source);
// 自定义属性
layer.get('name');
layer.set('name', 'NewName');
layer.getProperties();
// 获取所属地图
layer.getMapInternal();
3.2.4 Source 对象
Source 负责管理图层的数据来源:
import OSM from 'ol/source/OSM';
import XYZ from 'ol/source/XYZ';
import TileWMS from 'ol/source/TileWMS';
import WMTS from 'ol/source/WMTS';
import VectorSource from 'ol/source/Vector';
import ImageWMS from 'ol/source/ImageWMS';
// XYZ 瓦片源
const xyzSource = new XYZ({
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
maxZoom: 19,
crossOrigin: 'anonymous',
attributions: '© OpenStreetMap contributors',
// 瓦片相关配置
tileSize: [256, 256],
tilePixelRatio: 1,
cacheSize: 2048,
// 错误处理
reprojectionErrorThreshold: 0.5
});
// WMS 瓦片源
const wmsSource = new TileWMS({
url: 'http://localhost:8080/geoserver/wms',
params: {
'LAYERS': 'workspace:layer',
'TILED': true,
'FORMAT': 'image/png'
},
serverType: 'geoserver',
crossOrigin: 'anonymous'
});
// 矢量数据源
const vectorSource = new VectorSource({
url: 'data/geojson/points.geojson',
format: new GeoJSON(),
// 加载策略
strategy: bboxStrategy, // 或 allStrategy, tileStrategy
// 数据加载器
loader: function(extent, resolution, projection) {
// 自定义加载逻辑
},
// 属性名映射
attributions: '数据来源',
// 叠加模式
overlaps: true,
// 数据缓存
useSpatialIndex: true,
// 数据包裹
wrapX: true
});
Source 常用方法:
// 通用方法
source.getState(); // 'undefined' | 'loading' | 'ready' | 'error'
source.getAttributions();
source.getProjection();
source.refresh();
// 矢量源特有方法
vectorSource.addFeature(feature);
vectorSource.addFeatures(features);
vectorSource.removeFeature(feature);
vectorSource.clear();
vectorSource.getFeatures();
vectorSource.getFeatureById(id);
vectorSource.getFeaturesAtCoordinate(coordinate);
vectorSource.getFeaturesInExtent(extent);
vectorSource.forEachFeature(callback);
vectorSource.getExtent();
vectorSource.isEmpty();
vectorSource.getClosestFeatureToCoordinate(coordinate);
// 事件监听
vectorSource.on('addfeature', (event) => {
console.log('添加要素:', event.feature);
});
vectorSource.on('removefeature', (event) => {
console.log('移除要素:', event.feature);
});
vectorSource.on('change', () => {
console.log('数据源变化');
});
3.2.5 Feature 对象
Feature 表示地图上的单个要素:
import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
import LineString from 'ol/geom/LineString';
import Polygon from 'ol/geom/Polygon';
import { fromLonLat } from 'ol/proj';
import { Style, Fill, Stroke, Circle, Icon, Text } from 'ol/style';
// 创建点要素
const pointFeature = new Feature({
geometry: new Point(fromLonLat([116.4074, 39.9042])),
name: '北京',
population: 21540000
});
// 设置 ID
pointFeature.setId('beijing');
// 设置样式
pointFeature.setStyle(new Style({
image: new Circle({
radius: 10,
fill: new Fill({ color: 'red' }),
stroke: new Stroke({ color: 'white', width: 2 })
}),
text: new Text({
text: '北京',
offsetY: -20,
font: '14px sans-serif',
fill: new Fill({ color: '#333' })
})
}));
// 创建线要素
const lineFeature = new Feature({
geometry: new LineString([
fromLonLat([116.4074, 39.9042]),
fromLonLat([121.4737, 31.2304])
]),
name: '北京-上海'
});
// 创建面要素
const polygonFeature = new Feature({
geometry: new Polygon([[
fromLonLat([116.0, 39.0]),
fromLonLat([117.0, 39.0]),
fromLonLat([117.0, 40.0]),
fromLonLat([116.0, 40.0]),
fromLonLat([116.0, 39.0])
]]),
name: '区域A'
});
Feature 常用方法:
// ID 管理
feature.getId();
feature.setId(id);
// 几何操作
feature.getGeometry();
feature.setGeometry(geometry);
feature.getGeometryName();
feature.setGeometryName(name);
// 样式操作
feature.getStyle();
feature.setStyle(style);
feature.getStyleFunction();
// 属性操作
feature.get('name');
feature.set('name', value);
feature.getProperties();
feature.setProperties(properties);
feature.unset('name');
// 克隆
const cloned = feature.clone();
// 事件
feature.on('change', () => {
console.log('要素变化');
});
feature.on('change:geometry', () => {
console.log('几何变化');
});
3.3 事件系统
3.3.1 事件类型
OpenLayers 提供丰富的事件类型:
// Map 事件
map.on('click', (event) => {}); // 点击
map.on('dblclick', (event) => {}); // 双击
map.on('singleclick', (event) => {}); // 单击(无双击跟随)
map.on('pointermove', (event) => {}); // 指针移动
map.on('pointerdrag', (event) => {}); // 指针拖拽
map.on('movestart', (event) => {}); // 移动开始
map.on('moveend', (event) => {}); // 移动结束
map.on('postrender', (event) => {}); // 渲染完成
map.on('precompose', (event) => {}); // 渲染前
map.on('postcompose', (event) => {}); // 合成后
map.on('rendercomplete', (event) => {}); // 完全渲染完成
// View 事件
view.on('change:center', (event) => {}); // 中心点变化
view.on('change:zoom', (event) => {}); // 缩放变化
view.on('change:rotation', (event) => {}); // 旋转变化
view.on('change:resolution', (event) => {}); // 分辨率变化
// Layer 事件
layer.on('change:visible', (event) => {}); // 可见性变化
layer.on('change:opacity', (event) => {}); // 透明度变化
layer.on('change:source', (event) => {}); // 数据源变化
// Source 事件
source.on('change', (event) => {}); // 数据变化
source.on('addfeature', (event) => {}); // 添加要素
source.on('removefeature', (event) => {}); // 移除要素
source.on('changefeature', (event) => {}); // 要素变化
source.on('clear', (event) => {}); // 清空
// Collection 事件
collection.on('add', (event) => {}); // 添加元素
collection.on('remove', (event) => {}); // 移除元素
3.3.2 事件对象
// MapBrowserEvent(地图浏览器事件)
map.on('click', (event) => {
// 基本属性
console.log(event.type); // 事件类型
console.log(event.map); // 地图实例
console.log(event.coordinate); // 地图坐标
console.log(event.pixel); // 像素坐标
console.log(event.originalEvent); // 原生 DOM 事件
console.log(event.dragging); // 是否拖拽中
// 功能键状态
const origEvent = event.originalEvent;
console.log(origEvent.ctrlKey); // Ctrl 键
console.log(origEvent.shiftKey); // Shift 键
console.log(origEvent.altKey); // Alt 键
});
// 要素查询
map.on('click', (event) => {
// 获取点击位置的要素
map.forEachFeatureAtPixel(event.pixel, (feature, layer) => {
console.log('点击要素:', feature.get('name'));
console.log('所属图层:', layer);
return true; // 返回 true 停止遍历
});
// 检查是否有要素
const hasFeature = map.hasFeatureAtPixel(event.pixel);
// 获取所有要素
const features = map.getFeaturesAtPixel(event.pixel);
});
3.3.3 事件监听管理
import { unByKey } from 'ol/Observable';
// 添加事件监听
const key = map.on('click', clickHandler);
// 添加一次性事件监听
const onceKey = map.once('click', (event) => {
console.log('只触发一次');
});
// 移除事件监听 - 方式1:使用 key
unByKey(key);
// 移除事件监听 - 方式2:使用 un 方法
map.un('click', clickHandler);
// 批量添加事件监听
const keys = [
map.on('click', clickHandler),
map.on('pointermove', moveHandler),
map.on('moveend', moveEndHandler)
];
// 批量移除
keys.forEach(key => unByKey(key));
// 使用事件管理器类
class EventManager {
constructor() {
this.keys = [];
}
add(target, type, handler) {
const key = target.on(type, handler);
this.keys.push(key);
return key;
}
remove(key) {
const index = this.keys.indexOf(key);
if (index > -1) {
this.keys.splice(index, 1);
unByKey(key);
}
}
clear() {
this.keys.forEach(key => unByKey(key));
this.keys = [];
}
}
const eventManager = new EventManager();
eventManager.add(map, 'click', clickHandler);
eventManager.add(map, 'moveend', moveEndHandler);
// 清理所有事件
eventManager.clear();
3.3.4 自定义事件
import BaseObject from 'ol/Object';
// 创建自定义可观察对象
class CustomMapTool extends BaseObject {
constructor() {
super();
this.active = false;
}
activate() {
this.active = true;
this.dispatchEvent({
type: 'activate',
tool: this
});
}
deactivate() {
this.active = false;
this.dispatchEvent({
type: 'deactivate',
tool: this
});
}
complete(result) {
this.dispatchEvent({
type: 'complete',
result: result
});
}
}
// 使用自定义工具
const tool = new CustomMapTool();
tool.on('activate', (event) => {
console.log('工具已激活');
});
tool.on('deactivate', (event) => {
console.log('工具已停用');
});
tool.on('complete', (event) => {
console.log('操作完成:', event.result);
});
tool.activate();
tool.complete({ feature: newFeature });
tool.deactivate();
3.4 集合管理(Collection)
3.4.1 Collection 基础
import Collection from 'ol/Collection';
// 创建集合
const collection = new Collection();
// 带初始值创建
const collection2 = new Collection([item1, item2, item3]);
// 添加元素
collection.push(item);
collection.insertAt(0, item);
collection.extend([item1, item2]);
// 移除元素
collection.remove(item);
collection.removeAt(0);
collection.pop();
collection.clear();
// 访问元素
collection.item(0);
collection.getArray();
collection.getLength();
collection.forEach((item, index) => {});
// 查找
collection.indexOf(item);
// 集合事件
collection.on('add', (event) => {
console.log('添加元素:', event.element);
});
collection.on('remove', (event) => {
console.log('移除元素:', event.element);
});
collection.on('change:length', () => {
console.log('集合长度变化');
});
3.4.2 图层集合
// 获取图层集合
const layers = map.getLayers();
// 添加图层
layers.push(newLayer);
layers.insertAt(0, baseLayer);
// 移除图层
layers.remove(layer);
// 调整顺序
const index = layers.getArray().indexOf(layer);
layers.removeAt(index);
layers.insertAt(newIndex, layer);
// 遍历图层
layers.forEach((layer, index) => {
console.log(`图层 ${index}:`, layer.get('name'));
});
// 监听图层变化
layers.on('add', (event) => {
console.log('添加图层:', event.element);
});
layers.on('remove', (event) => {
console.log('移除图层:', event.element);
});
// 查找图层
function findLayerByName(name) {
let found = null;
layers.forEach((layer) => {
if (layer.get('name') === name) {
found = layer;
}
});
return found;
}
3.4.3 要素集合
import Collection from 'ol/Collection';
import Feature from 'ol/Feature';
// 创建要素集合(用于 Select 交互)
const selectedFeatures = new Collection();
// 绑定到 Select 交互
const selectInteraction = new Select({
features: selectedFeatures
});
// 监听选择变化
selectedFeatures.on('add', (event) => {
console.log('选中要素:', event.element);
});
selectedFeatures.on('remove', (event) => {
console.log('取消选中:', event.element);
});
// 程序化操作选择
selectedFeatures.clear(); // 清除所有选择
selectedFeatures.push(feature); // 添加选择
3.5 投影系统基础
3.5.1 内置投影
import { get as getProjection, transform, fromLonLat, toLonLat } from 'ol/proj';
// 获取投影对象
const wgs84 = getProjection('EPSG:4326'); // WGS84 经纬度
const webMercator = getProjection('EPSG:3857'); // Web Mercator
// 检查投影属性
console.log(webMercator.getCode()); // 'EPSG:3857'
console.log(webMercator.getUnits()); // 'm' (米)
console.log(webMercator.getExtent()); // 全球范围
console.log(webMercator.isGlobal()); // true
console.log(webMercator.getMetersPerUnit()); // 1
// 经纬度转 Web Mercator
const webMercatorCoord = fromLonLat([116.4074, 39.9042]);
// 结果: [12958752.49..., 4853167.35...]
// Web Mercator 转经纬度
const lonLatCoord = toLonLat([12958752.49, 4853167.35]);
// 结果: [116.4074..., 39.9042...]
// 通用坐标转换
const coord = transform(
[116.4074, 39.9042],
'EPSG:4326',
'EPSG:3857'
);
3.5.2 注册自定义投影
import { register } from 'ol/proj/proj4';
import proj4 from 'proj4';
// 定义投影(以 CGCS2000 为例)
proj4.defs('EPSG:4490', '+proj=longlat +ellps=GRS80 +no_defs');
// 定义高斯投影
proj4.defs('EPSG:4527', '+proj=tmerc +lat_0=0 +lon_0=117 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs');
// 注册到 OpenLayers
register(proj4);
// 使用自定义投影
import { get as getProjection } from 'ol/proj';
const cgcs2000 = getProjection('EPSG:4490');
console.log(cgcs2000.getCode()); // 'EPSG:4490'
3.6 渲染机制
3.6.1 渲染流程
┌─────────────────────────────────────────────────────────────┐
│ OpenLayers 渲染流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 触发渲染 │
│ │ │
│ ├── 视图变化(平移、缩放、旋转) │
│ ├── 图层变化(添加、移除、可见性) │
│ ├── 数据变化(要素增删改) │
│ └── 手动调用 map.render() │
│ │
│ 2. 准备阶段 │
│ │ │
│ ├── 计算当前视口范围 │
│ ├── 确定需要渲染的图层 │
│ └── 请求瓦片/要素数据 │
│ │
│ 3. 渲染阶段 │
│ │ │
│ ├── 按 zIndex 排序图层 │
│ ├── 逐图层渲染 │
│ │ ├── 瓦片图层:绘制瓦片 │
│ │ ├── 矢量图层:应用样式绘制要素 │
│ │ └── 图像图层:绘制图像 │
│ └── 合成最终图像 │
│ │
│ 4. 后处理 │
│ │ │
│ ├── 触发 postrender 事件 │
│ └── 触发 rendercomplete 事件 │
│ │
└─────────────────────────────────────────────────────────────┘
3.6.2 Canvas 渲染
// Canvas 渲染器是默认选项
// 每个图层在单独的 Canvas 上渲染
// 获取渲染器
const renderer = map.getRenderer();
// 渲染事件钩子
map.on('precompose', (event) => {
// 渲染前,可以访问 Canvas 上下文
const ctx = event.context;
ctx.save();
});
map.on('postcompose', (event) => {
// 渲染后,可以进行后处理
const ctx = event.context;
// 自定义绘制
ctx.restore();
});
// 手动渲染到 Canvas
map.on('rendercomplete', () => {
const canvas = document.createElement('canvas');
const size = map.getSize();
canvas.width = size[0];
canvas.height = size[1];
const context = canvas.getContext('2d');
// 合成所有图层
document.querySelectorAll('.ol-layer canvas').forEach((layerCanvas) => {
if (layerCanvas.width > 0) {
const opacity = layerCanvas.parentNode.style.opacity || 1;
context.globalAlpha = opacity;
const transform = layerCanvas.style.transform;
// 应用变换...
context.drawImage(layerCanvas, 0, 0);
}
});
// 导出图片
const dataUrl = canvas.toDataURL('image/png');
});
3.6.3 WebGL 渲染
import WebGLPointsLayer from 'ol/layer/WebGLPoints';
// 使用 WebGL 渲染大量点数据
const webglLayer = new WebGLPointsLayer({
source: new VectorSource({
features: generateManyPoints(100000)
}),
style: {
symbol: {
symbolType: 'circle',
size: 8,
color: 'red',
opacity: 0.8
}
}
});
map.addLayer(webglLayer);
// WebGL 样式表达式
const styleWithExpression = {
symbol: {
symbolType: 'circle',
size: ['interpolate', ['linear'], ['get', 'value'], 0, 5, 100, 20],
color: [
'interpolate',
['linear'],
['get', 'value'],
0, 'green',
50, 'yellow',
100, 'red'
],
opacity: 0.8
}
};
3.7 本章小结
本章深入介绍了 OpenLayers 的核心概念与架构设计:
- 设计理念:面向对象、可观察模式、属性系统、资源释放
- 核心对象:Map、View、Layer、Source、Feature
- 事件系统:事件类型、事件对象、事件管理
- 集合管理:Collection、图层集合、要素集合
- 投影系统:内置投影、自定义投影
- 渲染机制:渲染流程、Canvas 渲染、WebGL 渲染
关键要点
- 所有核心类都继承自 Observable,支持事件监听
- 使用 BaseObject 的属性系统管理配置
- 正确管理事件监听器避免内存泄漏
- 理解 Collection 在图层和要素管理中的作用
- 掌握 Canvas 和 WebGL 两种渲染方式的适用场景
下一步
在下一章中,我们将详细学习 Map 地图对象,包括:
- Map 创建与配置
- 地图方法详解
- 地图事件处理
- 地图导出与打印

浙公网安备 33010602011771号