OpenLayers 10.3.0 版本解读:WebGLVector 图层、SentinelHub 数据源、UTM 变换与 ImageTile 增强
2026/9/23 19:48:35 网站建设 项目流程
  • 前端
  • GIS
  • 数据可视化

【免费下载链接】openlayers

OpenLayers

项目地址:https://gitcode.com/gh_mirrors/op/openlayers
点击查看免费下载

OpenLayers 10.3.0 是一次以"新能力 + 破坏性升级"并重的重要版本:它引入了全新的WebGLVectorLayer(用于大规模矢量数据渲染)、内置 UTM 坐标变换支持、可直接对接欧洲航天局(ESA)哨兵影像服务的SentinelHub数据源,并为GeoTIFF数据源补齐了模型变换(旋转/倾斜/翻转瓦片网格)支持。同时,本版本包含两个需要升级注意的破坏性变更:transform()对未知投影不再静默降级,以及WebGLPointsLayer样式变量的声明位置调整。阅读完本文,你将掌握 10.3.0 全部新增 API 的用法、两个破坏性变更的迁移方案,以及背后的源码实现原理。

升级须知:两个破坏性变更

transform()函数对未知投影改为抛错

在 10.3.0 之前,src/ol/proj.js 中的transform()函数在遇到未注册的源投影或目标投影时,会静默应用"恒等变换"(identity transform),即把坐标原样返回。这很容易掩盖投影配置错误:例如把 EPSG:4326 的经纬度坐标交给一个拼错编码的投影,结果却是坐标"纹丝不动",导致地图位置完全错误且难以排查。

从 10.3.0 起,该函数在无法完成变换时会直接抛出Error。其实现位于 src/ol/proj.js#L620-L629:

export function transform(coordinate, source, destination) { const transformFunc = getTransform(source, destination); if (!transformFunc) { const sourceCode = get(source)?.getCode() ?? String(source); const destinationCode = get(destination)?.getCode() ?? String(destination); throw new Error( `No transform available between ${sourceCode} and ${destinationCode}`, ); } return transformFunc(coordinate, undefined, coordinate.length); }

迁移建议:在调用transform()之前,先通过ol/proj模块的get()函数检查投影是否已注册——get()在找不到给定标识符对应的投影定义时会返回null

import {get, transform} from 'ol/proj'; if (get('EPSG:32650') && get('EPSG:4326')) { const coord = transform([500000, 4649776], 'EPSG:32650', 'EPSG:4326'); }

这一变更同样会影响transformExtent()Geometry#transform()等所有底层依赖该函数的 API,请确保应用中涉及的所有投影编码都已通过proj4注册或内置支持(内置支持范围见下文 UTM 章节)。

WebGLPointsLayer样式格式变更:变量移至 options 根级

此前WebGLPointsLayer的样式变量(variables)被放在style对象内部,与filter混在一起:

// Before new WebGLPointsLayer({ style: { // variables were part of the `style` object variables: { minYear: 1850, maxYear: 2015, }, filter: ['between', ['get', 'year'], ['var', 'minYear'], ['var', 'maxYear']], }, source: vectorSource, })

从 10.3.0 起,变量必须作为独立的顶层对象传入options:

// Now new WebGLPointsLayer({ style: { filter: ['between', ['get', 'year'], ['var', 'minYear'], ['var', 'maxYear']], }, variables: { minYear: 1850, maxYear: 2015, }, source: vectorSource, })

值得注意的是,WebGLPointsLayer本身并不属于稳定 API(在 changelog/upgrade-notes.md 中也有明确说明),并且该图层在后续 10.4.0 版本中已被弃用,官方推荐使用本文接下来介绍的WebGLVectorLayer替代。如果你仍在使用WebGLPointsLayer,请按上述新格式迁移,并为迁移到WebGLVectorLayer做好准备。

新特性:WebGLVectorLayer图层

WebGLVectorLayer(源码位于 src/ol/layer/WebGLVector.js)是 10.3.0 引入的全新图层类,专门针对大规模矢量数据集的渲染进行优化,它使用 WebGL 渲染管线,比传统的 Canvas 矢量渲染拥有更高的吞吐能力。官方在其类注释中描述为 "Layer optimized for rendering large vector datasets"。

核心 API

该图层直接继承Layer,其OptionsWebGLPointsLayer类似,关键选项包括:

选项类型默认值说明
sourceVectorSource-矢量数据源
styleFlatStyleLike-扁平化样式(flat style),支持filter条件、['var', ...]['get', ...]等表达式
variablesStyleVariables{}样式变量,每个变量必须是字面值(非表达式),可在样式属性中通过['var', 'varName']引用
opacitynumber1图层不透明度
disableHitDetectionbooleanfalse设为true可带来轻微性能提升,但会禁用该图层上的所有命中检测
backgroundBackgroundColor-图层背景色
minZoom/maxZoomnumber-可见性控制

需要注意:WebGLVector图层在移除时必须手动调用dispose(),否则底层 WebGL 上下文不会被垃圾回收,造成资源泄漏。

从 src/ol/layer/WebGLVector.js#L79 的源码可以看到,构造时传入的variables被保存为私有属性this.styleVariables_,并提供了updateStyleVariables()方法用于运行时更新变量。

实战示例

examples/webgl-vector-layer.js 展示了完整的用法:使用多个扁平样式规则实现"高亮 + 默认 + 文本标注"三层样式,并通过updateStyleVariables()在鼠标移动时动态更新高亮变量:

const style = [ { filter: ['==', ['var', 'highlightedId'], ['id']], style: { 'stroke-color': 'white', 'stroke-width': 3, 'stroke-offset': -1, 'fill-color': [255, 255, 255, 0.4], }, }, { else: true, style: { 'stroke-color': ['*', ['get', 'COLOR'], [220, 220, 220]], 'stroke-width': 2, 'stroke-offset': -1, 'fill-color': ['*', ['get', 'COLOR'], [255, 255, 255, 0.6]], }, }, { style: { 'text-value': ['coalesce', ['get', 'ECO_NAME'], 'unknown'], 'text-font': 'bold 12px "Open Sans", "Arial Unicode MS", sans-serif', 'text-fill-color': 'rgb(0,0,0)', 'text-stroke-color': 'rgba(255, 255, 255, 0.8)', 'text-stroke-width': 2, 'text-overflow': false, }, }, ]; const vectorLayer = new WebGLVectorLayer({ source: new VectorSource({ url: 'https://openlayers.org/data/vector/ecoregions.json', format: new GeoJSON(), }), style, variables: { highlightedId: -1, }, }); // 运行时更新变量 vectorLayer.updateStyleVariables({highlightedId: id});

样式规则数组中的多条规则按顺序求值,filter命中即采用对应样式;['var', 'highlightedId']updateStyleVariables()的组合是 WebGL 系列图层实现交互高亮的标准模式。对应示例 examples/webgl-vector-layer.html 可直接运行查看效果。

新特性:SentinelHub数据源

SentinelHub(源码位于 src/ol/source/SentinelHub.js)是一个基于Sentinel Hub Processing API的瓦片数据源,它继承自DataTileSource,允许开发者用 JavaScript 编写 Evalscript,直接对欧空局哨兵(Sentinel)卫星影像执行波段运算并渲染为地图瓦片。

工作原理

从源码结构看,其工作流是"三步就绪"模式:构造时auth(认证)、data(输入数据)、evalscript(处理脚本)三者缺一不可,任一项缺失时数据源保持loading状态,不会渲染;三者齐备后由fireWhenReady_()将状态置为ready并触发渲染(src/ol/source/SentinelHub.js#L589-L600)。因此三个核心配置均提供了对应的 setter 方法以便延迟配置:

  • setAuth(auth):接受{clientId, clientSecret}对象(此时会请求 OAuth2 token)或直接传入 access token 字符串;token 过期前 60 秒会自动刷新(src/ol/source/SentinelHub.js#L500-L533);
  • setData(data):设置输入数据配置;
  • setEvalscript(evalscript):接受字符串形式的 Evalscript,或包含setup/evaluatePixel/updateOutput等函数的对象——对象形式会被serializeEvalscript()序列化成以//VERSION=3开头的脚本字符串提交给服务端执行;
  • setFormat(format):设置响应 MIME 类型。

瓦片加载时,源码通过loadTile_()向 Processing API 发起POST请求,请求体包含input.bounds.bbox(当前瓦片范围)、input.data(数据配置)、output(瓦片尺寸与响应格式)以及evalscript(src/ol/source/SentinelHub.js#L619-L684)。请求头使用Authorization: Bearer <token>。当遭遇 HTTP 429(限流)时,源码会忽略Retry-After头,改用指数退避策略重试(最多 10 次,基础延迟 500ms,即500ms × 2^attempt)。

核心配置参数

构造函数的Options完整定义见 src/ol/source/SentinelHub.js#L377-L398,要点如下:

选项类型默认值说明
authAuthConfig \| string-{clientId, clientSecret}或直接给 token;未提供时需后续调用setAuth()
dataArray<ProcessRequestInputDataItem>-输入数据配置,如{type: 'sentinel-2-l2a', dataFilter: {...}}
evalscriptEvalscript \| string-处理脚本,函数对象会被序列化为 Evalscript
tileSizenumber \| Size[512, 512]瓦片像素宽高
urlstringhttps://services.sentinel-hub.com/api/v1/processProcessing API 地址
formatstringimage/png响应 MIME 类型,仅支持image/pngimage/jpegimage/webp(源码中通过knownImageMediaTypes白名单校验,非法值会在构造时抛错)
projectionProjectionLike视图投影瓦片投影
wrapXbooleantrue是否跨反经线(东西方向环绕)渲染
interpolatebooleantrue重采样时是否使用线性插值,设为false使用最近邻

数据项的dataFilter支持timeRange{from, to}时间范围)和maxCloudCoverage(0-100 的最大云量)过滤;type可指定如sentinel-2-l2a等集合。坐标参考系通过getProjectionIdentifier()转换为 Sentinel Hub 接受的 OGC CRS URI 形式(如http://www.opengis.net/def/crs/EPSG/0/4326,src/ol/source/SentinelHub.js#L329-L351)。

实战示例

examples/sentinel-hub.js 演示了完整的接入流程——构造时只配置dataevalscript,认证凭据由用户通过表单提交后调用setAuth()注入:

useGeographic(); const source = new SentinelHub({ data: [ { type: 'sentinel-2-l2a', dataFilter: { timeRange: { from: '2024-05-30T00:00:00Z', to: '2024-06-01T00:00:00Z', }, }, }, ], evalscript: { setup: () => ({ input: ['B12', 'B08', 'B04'], output: {bands: 3}, }), evaluatePixel: (sample) => [ 2.5 * sample.B12, 2 * sample.B08, 2 * sample.B04, ], }, }); // 用户提交 clientId / clientSecret 后激活数据源 source.setAuth({clientId, clientSecret}); // 配置错误时通过 change 事件 + getError() 获取详细信息 source.on('change', () => { if (source.getState() === 'error') { alert(source.getError()); } });

上面的 Evalscript 使用 B12/B08/B04 三个波段做加权合成,模拟近红外假彩色影像。当数据源配置或认证失败时,源码会将状态置为error并触发change事件,通过getError()(src/ol/source/SentinelHub.js#L700-L702)可以拿到具体错误对象用于调试。仓库中还提供了 examples/sentinel-hub-custom-format.js(自定义image/jpeg格式)与 examples/sentinel-hub-custom-script.js(自定义脚本)两个变体示例。

ImageTile数据源的多项增强

10.3.0 对近期引入的ImageTile数据源(源码位于 src/ol/source/ImageTile.js)做了多项增强。ImageTileSource继承自DataTileSource,用于加载图片类型的瓦片,其核心特点是 URL 模板、数组或函数三种方式定义瓦片地址:

// 单一 URL 模板 new ImageTileSource({ url: 'https://example.com/tiles/{z}/{x}/{y}.png', }); // URL 数组(自动轮换负载均衡) new ImageTileSource({ url: ['https://a.example.com/{z}/{x}/{y}.png', 'https://b.example.com/{z}/{x}/{y}.png'], }); // 函数形式,完全自定义 URL 逻辑 new ImageTileSource({ url: (z, x, y) => `https://example.com/tiles/${z}/${x}/${y}.png`, });

源码内部会把字符串/数组形式的 URL 通过makeLoaderFromTemplates()renderXYZTemplate()展开为加载函数(src/ol/source/ImageTile.js#L63-L96);也支持直接提供自定义loader函数。在 10.3.0 中新增的关键增强包括:

  • zDirection选项:控制当视图分辨率处于两个整数缩放级别之间时,选择更高还是更低的瓦片级别,可传数字或NearestDirectionFunction(src/ol/source/ImageTile.js#L48-L51);
  • {-y}占位符修复:修复了{-y}(翻转 Y 坐标)占位符在ImageTile源中的处理错误,使其与XYZ等源行为一致;
  • TileDebug改为ImageTile的子类:调试瓦片网格图层从此前的XYZ基类迁移到ImageTile基类,便于与新的图片瓦片体系配合调试;
  • 属性/选项补充transition(新瓦片淡入时长)、interpolatecrossOriginreferrerPolicy等均可在构造时配置。

仓库中的 examples/pmtiles-image.js 演示了如何从 PMTiles 归档读取图片瓦片并喂给ImageTile源,展示了loader自定义加载的典型场景。

GeoTIFF数据源的模型变换支持

10.3.0 为GeoTIFF数据源(源码位于 src/ol/source/GeoTIFF.js)新增了模型变换(model transformation)支持,使其能够正确处理旋转、倾斜或翻转(flipped)的瓦片网格。此前这类非标准网格的 GeoTIFF 影像(例如某些合成孔径雷达 SAR 产品)无法被正确配准到地图上。

在源码中,当 TIFF 的fileDirectory中带有ModelTransformation标签时,会读取其 4×4 仿射变换矩阵的前 8 个元素,并据此调整瓦片网格的配准(src/ol/source/GeoTIFF.js#L637-L642):

const modelTransformation = image.fileDirectory.getValue( // ... GeoTIFF ModelTransformation tag 读取 ); if (modelTransformation) { const [a, b, c, d, e, f, g, h] = modelTransformation; // 依据该矩阵构造旋转/倾斜/翻转感知的网格变换 }

仓库中的 examples/cog-modeltransformation.js 展示了直接加载一张带模型变换的 Cloud Optimized GeoTIFF(来自 UMBRA 开放 SAR 数据目录)并叠加在 OSM 底图上的完整流程:通过cogSource.getView()获取源投影与范围,配合proj4注册自定义投影,再用transformExtent()将源范围变换到视图投影后fit到视口:

register(proj4); const cogSource = new GeoTIFF({ sources: [{url: 'https://umbra-open-data-catalog.s3.amazonaws.com/.../xxx_GEC.tif'}], }); // ... 创建地图并叠加底图 ... cogSource.getView().then((viewConfig) => fromProjectionCode(viewConfig.projection.getCode()).then(() => { const view = map.getView(); view.fit( transformExtent( viewConfig.extent, viewConfig.projection, view.getProjection(), ), ); }), );

内置 UTM 坐标变换

10.3.0 在ol/proj中加入了开箱即用的 UTM 投影支持(实现位于 src/ol/proj/utm.js),无需额外注册 proj4 定义即可在 UTM 投影与经纬度之间互转。

支持的投影编码与判定逻辑

源码中的zoneFromCode()(src/ol/proj/utm.js#L210-L236)通过正则识别以下三种编码形式:

  • EPSG:326XX—— 北半球 UTM 带(如 EPSG:32650 为北半球 50 带);
  • EPSG:327XX—— 南半球 UTM 带(如 EPSG:32750 为南半球 50 带);
  • urn:ogc:def:crs:EPSG::XXXXhttp://www.opengis.net/def/crs/EPSG/0/XXXX形式的等价 URI。

其中 32601–32660 判定为北半球,32701–32760 判定为南半球。makeProjection()makeTransforms()(src/ol/proj/utm.js#L270-L292)分别负责创建投影实例(单位为米)与正反变换函数,fromLonLat()/toLonLat()内部实现了基于 WGS84 椭球(长半轴 6378137m)的标准横轴墨卡托算法,中央经线通过zoneToCentralLongitude()(zone - 1) * 6 - 180 + 3)计算,东偏移量为 500000m,南半球北偏移量附加 10000000m,比例因子K0 = 0.9996

使用方式

import {transform} from 'ol/proj'; // 经纬度 → UTM 北半球 50 带 const utm = transform([116.39, 39.9], 'EPSG:4326', 'EPSG:32650'); // UTM → 经纬度 const lonLat = transform(utm, 'EPSG:32650', 'EPSG:4326');

需要说明的是,源码注释明确指出这套算法提供的是近似变换:"The functions here provide approximate transforms to and from UTM. They are not appropriate for use beyond the validity extend of a UTM zone, and the accuracy of the transform decreases toward the zone edges." 即其精度在远离所在带中央经线时会下降,不适合超出带有效范围使用;对精度要求严苛的场景仍建议使用 proj4 注册完整定义。同时,fromLonLat()会将纬度钳制在 -80°~84° 之间,这与 UTM 系统的有效范围一致。

渲染与性能改进

常规形状与图标样式的智能缓存

10.3.0 将常规形状(RegularShape)样式接入IconImageCache(相关改动见 PR #16349,配套的 PR #16362 使用Math.ceil()计算常规形状的画布尺寸)。这意味着大量使用同一形状/图标样式的地图(如海量点标注)可以共享缓存图像,避免重复绘制,显著降低渲染开销与内存占用;同时使用Math.ceil()取整画布尺寸,规避了亚像素导致的渲染毛边。

VectorImageLayer的 TypeScript 泛型修复

PR #16348 修复了VectorImageLayer(源码位于 src/ol/layer/VectorImage.js)的类型泛型定义,使其能够正确推导出图层关联矢量数据源的特征类型。对 TypeScript 用户而言,new VectorImageLayer({source})getSource()返回的特征类型不再退化为FeatureLike,IDE 提示与类型检查更加精准。

渲染事件与可见性语义

  • PostRenderFunctionFrameState永不为 null(PR #16415):此前在某些场景下 postrender 回调拿不到frameState,现在postrender函数始终能获得有效帧状态;配套改动(PR #16268、#16277)确保在没有帧状态时不调用 postrender 函数,并支持在 Worker 中执行 postrender 函数;
  • isVisible()语义调整(PR #16260):尚未完成渲染的图层,isVisible()现在返回false,避免在首帧渲染前产生错误的可见性判断;
  • 使用event.pixel替代getEventPixel(PR #16395):简化了事件坐标的获取路径。

文本标注与图层选项

  • keepUpright参数(PR #16302、#16315):新增text-keep-upright扁平样式属性,控制文本标签在旋转视图/旋转要素上是否保持直立,避免倒置文字影响可读性;
  • 恢复setDeclutter()方法(PR #16383):ol/layer/Vector重新支持通过setDeclutter()动态开关标签去重(declutter);
  • background进入Tile图层选项(PR #16371):瓦片图层现在可以直接配置背景色;
  • overlaps选项的 setter(PR #16243):为相关图层/渲染器补充了overlaps的运行时设置方法;
  • URI 组件编码修复(PR #16409):修正了 URL/URI 组件未正确编码的问题,避免含特殊字符的请求地址失效。

其他值得关注的变化

  • 投影与 OGC 服务:OGC TileMatrixSet 的crs现在可以接受带 URI 字符串的 CRS 对象(PR #16291),并可从 TileMatrixSet 的 CRS 自动设置源投影(PR #16293);
  • 命中检测修正(PR #16393):hitDetection只对点要素生效,避免对线/面产生误判;
  • Modify交互 API 改进(PR #16296):程序化调用 Modify 交互的接口更完善;
  • 数据压缩库替换(PR #16254):用fflate替换jszip,减小打包体积;
  • RBushforEach支持模板参数(PR #16345):类型层面增强;
  • 依赖升级proj4升级到 2.15.0、typescript升级到 5.7.2、jsts升级到 2.12.1、rollup升级到 4.27.4 等(完整列表见 changelog/v10.3.0.md 的 Dependency Updates 小节)。

迁移总结

升级到 10.3.0 时,需要重点检查两处:

  1. 投影变换调用:确认所有transform()调用涉及的投影编码都已注册(get(code) !== null),否则会抛出No transform available between ...错误;
  2. WebGLPointsLayer样式:将style.variables迁移到 options 根级,并留意该图层 API 不稳定、官方后续推荐WebGLVectorLayer的事实。

对于新项目,建议直接采用WebGLVectorLayer+ 扁平样式 +updateStyleVariables()的方案处理大规模矢量数据,用SentinelHub数据源接入哨兵影像处理流程,并利用开箱即用的 UTM 变换简化投影处理代码。

  • 前端
  • GIS
  • 数据可视化

【免费下载链接】openlayers

OpenLayers

项目地址:https://gitcode.com/gh_mirrors/op/openlayers
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询