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。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>OpenLayers</title>
    <style>
      html, body, #map-container {
        margin: 0;
        height: 100%;
        width: 100%;
        font-family: sans-serif;
        background-color: #04041b;
      }
    </style>
  </head>
  <body>
    <div id="map-container"></div>
  </body>
</html>

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

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

JavaScript代码如下

import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON';
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';

new Map({
  target: 'map-container',
  layers: [
    new VectorLayer({
      source: new VectorSource({
        format: new GeoJSON(),
        url: './data/countries.json'
      })
    })
  ],
  view: new View({
    center: [0, 0],
    zoom: 2
  })
});

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

//

由于我们将大量重新加载页面,如果地图停留在我们重新加载时离开的位置,那就太好了。我们可以引入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();

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

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

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

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

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

拖放

编辑要素

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

首先引入Modify

import Modify from 'ol/interaction/Modify';

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

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

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

修改特征

绘制新要素

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

首先在js里引入Draw

import Draw from 'ol/interaction/Draw';

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

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

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';

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

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

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

通过快速互动联合国家

下载

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

html里添加下面

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

为上边的按钮添加样式

#tools {
  position: absolute;
  top: 1rem;
  right: 1rem;
}
#tools a {
  display: inline-block;
  padding: 0.5rem;
  background: white;
  cursor: pointer;
}

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

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

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

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

修改样式

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

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

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

静态样式

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

const layer = new VectorLayer({
  source: source,
  style: new Style({
    fill: new Fill({
      color: 'red'
    }),
    stroke: new Stroke({
      color: 'white'
    })
  })
});

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

动态样式

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

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

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

根据几何面积样式化

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

import {getArea} from 'ol/sphere';
import colormap from 'colormap';

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

const min = 1e8; // 最小面积
const max = 2e13; // 最大面积
const steps = 50;
const ramp = colormap({
  colormap: 'blackbody',
  nshades: steps
});

function clamp(value, low, high) {
  return Math.max(low, Math.min(value, high));
}

function getColor(feature) {
  const area = getArea(feature.getGeometry());
  const f = Math.pow(clamp((area - min) / (max - min), 0, 1), 1 / 2);
  const index = Math.round(f * (steps - 1));
  return ramp[index];
}

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

const layer = new VectorLayer({
  source: source,
  style: function(feature) {
    return new Style({
      fill: new Fill({
        color: getColor(feature)
      }),
      stroke: new Stroke({
        color: 'rgba(255,255,255,0.8)'
      })
    });
  }
});

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值