当前位置:   article > 正文

OpenLayers官网教程-矢量数据_openlayers中文网

openlayers中文网

这一系列翻译自openlayers官网的WorkShop。OL官网提供了多个系列教程供开发者学习参考,其中QuickStart是面向初学者的hello world,Tutorials提供了构建OL应用的一些基础知识,WorkShop(本系列)详细介绍了一些入门向的高阶应用,最后是APIDocs,适合开发时查阅接口。教程中需要下载的资源可以在WorkShop原网站获得链接。

在这一章节,我们将编写一个矢量数据编辑工具。该工具可以供使用者引入数据,绘制新的矢量要素,修改现有矢量要素,以及导出结果。本章教程的样例数据采用的是GeoJSON格式,不过OpenLayers也支持大量其他的矢量数据格式。

  1. 渲染GeoJSON
  2. 拖拽加载数据
  3. 编辑要素
  4. 绘制新要素
  5. 边缘吸附
  6. 下载
  7. 修改样式

渲染GeoJSON

在实现矢量编辑之前,我们先引入矢量数据,使用VectorSource和Layer将其渲染在地图上。教程包含了一个 countries.json GeoJSON文件,我们首先将他加载到地图上。

首先,html页面需要一个用以承载地图的div。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>OpenLayers</title>
  6. <style>
  7. html, body, #map-container {
  8. margin: 0;
  9. height: 100%;
  10. width: 100%;
  11. font-family: sans-serif;
  12. background-color: #04041b;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <div id="map-container"></div>
  18. </body>
  19. </html>

现在我们将导入处理矢量数据的三个重要组件:

  • 用于读取和写入序列化数据的格式(format)
  • 用于获取数据和管理要素空间索引的矢量数据源(source)
  • 用于在地图上渲染要素的矢量图层(layer)

JavaScript代码如下

  1. import 'ol/ol.css';
  2. import GeoJSON from 'ol/format/GeoJSON';
  3. import Map from 'ol/Map';
  4. import VectorLayer from 'ol/layer/Vector';
  5. import VectorSource from 'ol/source/Vector';
  6. import View from 'ol/View';
  7. new Map({
  8. target: 'map-container',
  9. layers: [
  10. new VectorLayer({
  11. source: new VectorSource({
  12. format: new GeoJSON(),
  13. url: './data/countries.json'
  14. })
  15. })
  16. ],
  17. view: new View({
  18. center: [0, 0],
  19. zoom: 2
  20. })
  21. });

完成后结果应该是下图这样

//

由于我们将大量重新加载页面,如果地图停留在我们重新加载时离开的位置,那就太好了。我们可以引入ol-hashed来完成这项工作。此软件包已作为教程依赖项的一部分安装。如果尚未包含,您可以使用npm install ol-hashed

然后在js里导入

import sync from 'ol-hashed';

现在我们需要将地图分配给一个变量(命名map),以便我们可以将该变量传递给sync函数

const map = new Map({

现在我们可以使用sync同步我们的地图

sync(map);

现在页面重新加载后地图视图应该会保持原样,后退操作也能如期进行。

拖拽加载数据

对于我们的要素编辑工具,我们希望用户能够导入自己的数据进行编辑。我们将使用DragAndDrop添加这种交互。和以前一样,我们将使用 GeoJSON 格式来解析要素,但其他矢量格式也可以进行下面的操作。

我们将在本章节中将地图传递给许多其他组件,因此请确保您已将地图分配给名为map的变量。

首先在js里引入DragAndDrop模块

import DragAndDrop from 'ol/interaction/DragAndDrop';

接下来,我们将创建一个没有初始数据的矢量数据源。该数据源将存储用户拖放到地图上的要素,而不是像前面的示例那样加载外部数据。

const source = new VectorSource();

现在使用新的数据源创建一个矢量图层,将其添加到地图上

  1. const layer = new VectorLayer({
  2. source: source
  3. });
  4. map.addLayer(layer);

最后,我们将创建一个拖放交互,将矢量数据源配置进去,并将其添加到地图中

  1. map.addInteraction(new DragAndDrop({
  2. source: source,
  3. formatConstructors: [GeoJSON]
  4. }));

现在应该可以将GeoJSON 文件拖放到地图上直接加载

拖放

编辑要素

现在用户可以将数据拖拽加载到编辑工具中,我们希望用户可以编辑要素。我们将引入Modify这个交互组件,将刚才的矢量数据源配置进去

首先引入Modify

import Modify from 'ol/interaction/Modify';

接下来,为地图对象添加一个连接到矢量数据源的交互

  1. map.addInteraction(new Modify({
  2. source: source
  3. }));

将数据添加到地图后,可以通过拖动要素节点来修改位置,以及Alt+Click来删除节点

修改特征

绘制新要素

目前我们的要素编辑工具可以加载并编辑要素,接下来添加Draw组件用以绘制新要素并添加到数据源中。

首先在js里引入Draw

import Draw from 'ol/interaction/Draw';

然后为地图对象添加绘制交互,将数据源配置进去

  1. map.addInteraction(new Draw({
  2. type: 'Polygon',
  3. source: source
  4. }));

Draw对象的type属性控制该交互绘制什么类型的几何。该值可以是任何GeoJSON几何类型。这里也可以引入OL的几何类型枚举(import GeometryType from 'ol/geom/GeometryType';),然后使用GeometryType.POLYGON代替上边的polygon字符串。

现在应该可以使用绘制功能在数据源中添加新的要素。

A new island nation in the Caribbean

边缘吸附

您可能已经注意到,绘制与现有要素不一致的新要素很容易。此外,在修改要素时,我们可以打破拓扑——在之前相邻的多边形之间添加空隙。

首先引入Snap交互

import Snap from 'ol/interaction/Snap';

和之前的交互一样,添加到地图上

  1. map.addInteraction(new Snap({
  2. source: source
  3. }));

在绘制、修改和吸附交互都激活的情况下,可以在保持拓扑结构的同时编辑要素

通过快速互动联合国家

下载

上传数据并编辑后,我们想让用户可以下载结果。为此需要将矢量要素序列化为GeoJSON并在html里创建<a>标签让用户下载。同时,在页面加个按钮让用户可以清除现有要素重新绘制。

html里添加下面

  1. <div id="tools">
  2. <a id="clear">Clear</a>
  3. <a id="download" download="features.json">Download</a>
  4. </div>

为上边的按钮添加样式

  1. #tools {
  2. position: absolute;
  3. top: 1rem;
  4. right: 1rem;
  5. }
  6. #tools a {
  7. display: inline-block;
  8. padding: 0.5rem;
  9. background: white;
  10. cursor: pointer;
  11. }

要素的清除可以通过source.clear() 方法,为clear按钮添加监听触发清除函数

  1. const clear = document.getElementById('clear');
  2. clear.addEventListener('click', function() {
  3. source.clear();
  4. });

为了序列化我们的要素数据以供下载,我们将使用GeoJSON格式(format,之前引用的)。这里监听了数据源的变化,随时重写下载的uri

  1. const format = new GeoJSON({featureProjection: 'EPSG:3857'});
  2. const download = document.getElementById('download');
  3. source.on('change', function() {
  4. const features = source.getFeatures();
  5. const json = format.writeFeatures(features);
  6. download.href = 'data:text/json;charset=utf-8,' + json;
  7. });

修改样式

此时,我们有一个具有基本导入、编辑和导出功能的要素编辑器。但是我们没有花时间让它看起来好看。在 OpenLayers 中创建矢量图层时,会默认添加一组样式。编辑交互(绘制和修改)也有自己的默认样式。下面通过样式(Style)修改默认的图层样式。

首先引入样式(style),填充(fill)和路径(stroke)

import {Style, Fill, Stroke} from 'ol/style';

静态样式

如果想给一个图层里所有要素同样的样式,可以这样配置

  1. const layer = new VectorLayer({
  2. source: source,
  3. style: new Style({
  4. fill: new Fill({
  5. color: 'red'
  6. }),
  7. stroke: new Stroke({
  8. color: 'white'
  9. })
  10. })
  11. });

也可以将style设置为样式数组,形成比如下边一条宽线上边一条窄线这种样式。

动态样式

若想根据要素的属性字段或当前视图分辨率等来配置不同的样式,可以使用样式函数配置矢量图层。这个函数在每个要素的渲染帧都会被调用,所以如果你有很多要素属性并且想要保持良好的渲染性能,那么编写一个高效的函数很重要。

这里示例了根据‘name’属性的开头是‘A-M’还是‘N-Z’来渲染不同的样式

  1. const layer = new VectorLayer({
  2. source: source,
  3. style: function(feature, resolution) {
  4. const name = feature.get('name').toUpperCase();
  5. return name < "N" ? style1 : style2; // 假设这两个style是在别处创建的
  6. }
  7. });

根据几何面积样式化

为了了解动态样式的工作原理,我们将创建一个样式函数,该函数根据几何面积呈现特征。为此,我们将使用npm 上的一个colorMap包,安装(npm install colormap
)后导入js,使用ol/sphere进行球面面积计算

  1. import {getArea} from 'ol/sphere';
  2. import colormap from 'colormap';

下面的函数用以根据几何图形的面积确定颜色

  1. const min = 1e8; // 最小面积
  2. const max = 2e13; // 最大面积
  3. const steps = 50;
  4. const ramp = colormap({
  5. colormap: 'blackbody',
  6. nshades: steps
  7. });
  8. function clamp(value, low, high) {
  9. return Math.max(low, Math.min(value, high));
  10. }
  11. function getColor(feature) {
  12. const area = getArea(feature.getGeometry());
  13. const f = Math.pow(clamp((area - min) / (max - min), 0, 1), 1 / 2);
  14. const index = Math.round(f * (steps - 1));
  15. return ramp[index];
  16. }

下面为图层添加基于几何面积填充颜色的样式

  1. const layer = new VectorLayer({
  2. source: source,
  3. style: function(feature) {
  4. return new Style({
  5. fill: new Fill({
  6. color: getColor(feature)
  7. }),
  8. stroke: new Stroke({
  9. color: 'rgba(255,255,255,0.8)'
  10. })
  11. });
  12. }
  13. });

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/513746
推荐阅读
相关标签
  

闽ICP备14008679号