原文链接及内容

原文链接:https://openlayers.org/doc/tutorials/ ,这里将三部分内容合并翻译

基本概念

Map

OpenLayers的核心组件是Map(来自ol/Map模块)。它会在一个目标容器中进行渲染(例如,包含地图的Web页面上的div元素)。所有关于的map(对象)的属性可以在构造(实例对象)时配置,也可以使用setter方法,例如setTarget()
下面的HTML标记可以用来创建包含地图的<div>

1
<div id="map" style="width: 100%, height: 400px"></div>

下面的脚本构造了一个在<div>中渲染的地图(对象),使用上述divid属性作为选择器。

1
2
3
import Map from 'ol/Map.js';

const map = new Map({target: 'map'});

View

Map的实例对象不能控制地图的中心(center)、缩放级别(zoom)和投影(projection)等属性。相反,这些是ol/View实例对象的属性。

1
2
3
4
5
6
import View from 'ol/View.js';

map.setView(new View({
center: [0, 0],
zoom: 2,
}));

地图视图(View)也有投影(projection属性)。投影决定了中心(center属性)的坐标系和地图分辨率计算的单位。如果未指定(如上面的代码块所示),则默认投影为球面墨卡托(EPSG:3857),并使用作为地图的单位。
缩放(zoom)选项是指定地图分辨率的便捷方法。可用的缩放级别由maxZoom(默认设置为28)、zoomFactor(默认设置为2)和maxResolution(默认设置为投影的有效范围适合256x256像素的切片)确定。从缩放级别0开始,分辨率为每个像素的maxResolution单位,通过将前一个缩放级别的分辨率除以zoomFactor来计算后续的缩放级别,直到缩放级别达到maxZoom

Source

为了获取一个图层的远程数据,OpenLayers使用ol/source/Source子类,它们可用于免费和商业地图切片服务,如OpenStreetMap或Bing,OGC源,如WMS或WMTS,以及GeoJSON或KML格式的矢量数据。

1
2
3
import OSM from 'ol/source/OSM.js';

const source = OSM();

Layer

一个图层是某个来源的数据的可视化表示。OpenLayers有4种基本类型的层:

  • ol/layer/Tile:渲染在网格(grids)中提供的平铺的图像(tiled images)数据源,这些网格按特定分辨率的缩放级别进行组织。
  • ol/layer/Image:渲染以任意范围和分辨率提供地图图像的数据源。
  • ol/layer/Vector:在客户端渲染矢量数据。
  • ol/layer/VectorTile:渲染以矢量切片形式提供的数据。
1
2
3
4
5
import TileLayer from 'ol/layer/Tile.js';

// ...
const layer = new TileLayer({source: source});
map.addLayer(layer);

将上述概念放一起(举例)

上面的代码块可以组合到一个脚本中,该脚本可以使用单个切片图层来渲染地图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import OSM from 'ol/source/OSM.js';
import TileLayer from 'ol/layer/Tile.js';

new Map({
layers: [
new TileLayer({source: new OSM()}),
],
view: new View({
center: [0, 0],
zoom: 2,
}),
target: 'map',
});

关于Openlayers的一些背景知识

概述

OpenLayers是一个模块化、高性能、功能丰富的库,用于显示地图和地理空间数据,并且可以与其进行交互。
该库内置支持广泛的商业和免费的图像和矢量切片数据源,以及最流行的开放和专有矢量数据格式。有了OpenLayers地图投影的支持,数据可以放置在任何投影中。

公共API

OpenLayers以ol npm package的形式提供,它提供了官方支持的API的所有模块。

浏览器支持

OpenLayers可以在所有现代浏览器上运行(全球使用率超过1%),包括Chrome、Firefox、Safari和Edge。对于较旧的浏览器,可能需要添加polyfills
该库适用于桌面、笔记本电脑和移动设备,并支持指针和触摸交互。

模块和命名约定

采用CamelCase形式命名的OpenLayers模块提供类作为默认导出,并且可能包含额外的常量或函数作为命名导出:

1
2
import Map from 'ol/Map.js';
import View from 'ol/View.js';

在包的子目录中提供了按其父级分组的类层次结构,例如layer/
为方便起见,这些也可作为命名导出使用,例如

1
2
import {Map, View} from 'ol';
import {Tile, Vector} from 'ol/layer.js';

除了这些重新导出的类之外,具有小写名称的模块还提供了常量或函数作为命名导出:

1
2
import {getUid} from 'ol';
import {fromLonLat} from 'ol/proj.js';

栅格数据重投影

OpenLayers能够在不同的坐标系统中显示来自WMS、WMTS、静态影像和许多其他来源的栅格数据。影像投影转换会直接在Web浏览器中进行。并且地图视图(view)可以在任何Proj4js支持的坐标参考系统中展示,以前不兼容的图层现在也可以组合和叠加。

用法

API的使用非常简单,只需在ol/View上指定适当的投影(例如使用EPSG代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import Map from 'ol/Map.js';
import TileLayer from 'ol/layer/Tile.js';
import TileWMS from 'ol/source/TileWMS.js';
import View from 'ol/View.js';

const map = new Map({
target: 'map',
view: new View({
projection: 'EPSG:3857', // here is the view projection
center: [0, 0],
zoom: 2,
}),
layers: [
new TileLayer({
source: new TileWMS({
projection: 'EPSG:4326', // here is the source projection
url: 'https://ahocevar.com/geoserver/wms',
params: {
'LAYERS': 'ne:NE1_HR_LC_SR_W_DR',
},
}),
}),
],
});

如果一个数据源(基于ol/source/TileImageol/source/Image)的投影不同于当前ol/View的投影,底层则会自动重新投影。

例子

自定义投影

使用自定义投影的最简单方法是将Proj4js库添加到项目中,然后使用proj4定义字符串来定义投影。输入以下命令安装:

1
npm install proj4

下面的例子将展示British National Grid坐标系的定义:

1
2
3
4
5
6
7
8
9
10
11
import proj4 from 'proj4';
import {get as getProjection} from 'ol/proj.js';
import {register} from 'ol/proj/proj4.js';

proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' +
'+x_0=400000 +y_0=-100000 +ellps=airy ' +
'+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 ' +
'+units=m +no_defs');
register(proj4);
const proj27700 = getProjection('EPSG:27700');
proj27700.setExtent([0, 0, 700000, 1300000]);

地图视图(View)投影的更改

要切换用于显示地图的投影,你必须在ol/Map上配置一个新的ol/View,并配置新的投影:

1
2
3
4
5
map.setView(new View({
projection: 'EPSG:27700',
center: [400000, 650000],
zoom: 4,
}));

切片格网和范围(TileGrid and Extents)

当需要重新投影时,在底层新的地图切片(即在目标投影中的切片)会被来自原始数据源的切片所创建,默认情况下,重新投影的地图切片的TileGrid将默认使用ol/tilegridgetForProjection(Projection)进行构建。投影应该定义一个范围(即extent,见上文中自定义投影这一小节),这样才能正常工作。
或者,可以手动构建自定义目标投影的TileGrid,并使用ol/source/TileImagesetTileGridForProjection(projection,tileggrid)方法在数据源实例上进行设置。然后,在重新投影需要指定投影时将会使用手动构建的TileGrid而不是创建的默认TileGrid。在某些情况下,这可用于优化性能(通过调整切片大小)或视觉质量(通过指定分辨率)。

工作原理

重投影的过程基于三角形—即目标栅格被分成有限数量的三角形,其中的顶点使用ol/proj功能进行转换(通常使用proj4js来定义自定义转换),而三角形内部像素的重新投影近似于仿射变换(affine transformation,借助canvas使用硬件加速进行渲染):

通过这种方式,我们可以用相对较少的实际转换计算,在几乎任何硬件上支持来自proj4js(甚至是自定义转换函数)的各种投影(具有Canvas 2D支持)。
但是,重投影的精度受到三角形数量的限制。
重投影过程保持了原栅格数据(如png或gif)的透明度,重投影产生的间隙和无数据像素会自动变透明。

动态三角测量(Dynamic triangulation)

上面的示例图片有一个明显的错误(特别是在边缘),当原始图像(左图,EPSG: 27700)仅用有限数量的三角形(右图,EPSG: 3857)进行变换时。通过增加所使用的三角形的数量可以使误差最小化。
由于某些变换需要更详细的三角测量网络,因此动态三角测量过程会自动测量重投影误差并迭代细分以满足特定的误差阈值:

为了调试,可以通过ol.source.TileImage下的setRenderReprojectionEdges(true)方法来启用重投影边缘的渲染。

进一步地理解

三角测量精度阈值(Triangulation precision threshold)

上述默认的三角测量误差阈值(以像素为单位)由ERROR_THRESHOLD(0.5像素)给出,如果需要为不同的数据源定义不同的阈值,则可以在构造切片图像数据源时配置reprojectionErrorThreshold选项。

按范围限制重新投影地图的可见性(Limiting visibility of reprojected map by extent)

重投影算法采用的时逆变换(inverse transformation,从地图视图投影到数据投影)。对于某些坐标系,这可能导致源数据在地图上“两次出现”。例如,当将瑞士地图从EPSG:21781重新投影到EPSG:3857时,它会显示两次:一次是在欧洲的适当位置,另一次是在地球另一端新西兰附近的太平洋上。

虽然逆变换在数学上是没问题的,但用户并不期望在多个地方看到图层。一个可能的通用解决方案是,同时计算每个顶点的正向转换—但这将显著降低性能(特别是对于计算量大的转换)。
因此,一个推荐的解决方案是,在视图投影中的ol.layer.Tile上定义一个适当的可见范围。重投影演示示例演示了如何设置这样的限制。

分辨率计算(Resolution calculation)

在切片数据加载时,需要计算一个理想的数据源的分辨率。可以使用ol/reproj下的calculateSourceResolution(sourceProj, targetProj, targetCenter, targetResolution)函数来计算理想值,以便在重新投影期间实现尽可能接近1:1的像素绘制,然后为数据源选择适当的缩放级别。
然而,对于整个目标缩放级别使用相同的源缩放级别通常是不现实的——不同的投影在世界的不同地方可能有明显不同的分辨率(例如EPSG:3857的极地地区 vs EPSG:4326),对整个地图的缩放级别强制使用单一分辨率将导致一些切片被放大或缩小,可能造成需要加载大量的数据源切片。因此,分辨率绘制(resolution mapping,这里不确定怎么翻译)是为每个重新投影的切片(在切片范围的中间)单独计算的。


评论
avatar
风停在左肩
生活原本沉闷,但跑起来就有风
公告
近期一直在复现、学习Cesium的官方示例,先快速过一遍示例,复杂的或看不懂的可以放之后再过一遍。
最新文章
网站资讯
文章数目 :
386
已运行时间 :
本站总字数 :
300.2k
本站访客数 :
本站总访问量 :
最后更新时间 :