02 教程

作者: 无敌小菜鸟 | 来源:发表于2020-04-28 11:05 被阅读0次

1.发送一个OpenLayers申请

介绍

现代JavaScript在使用和编写组件时最好使。使用OpenLayers推荐安装 ol 包。这篇教程指导你安装一个简单的开发环境,这个过程中需要使用node

在本教程中,我们用Parcel打包应用。还有一些其它的设置,可以在README中找到一些。

初始化步骤

为你的项目新建一个空白目录,并且通过运行mkdir new-project && cd new-project找到它。使用下列代码进行初始化:

npm init

这一步会在你的工作目录中生成一个package.json的文件,通过下列代码为你的申请添加OpenLayers支持:

npm install ol

此时你可以通过运行以下代码访问NPM来添加必需的开发支持:

npm install --save-dev parcel-bundler

请求代码和index.HTML

在index.js中放入你的申请代码,这是一个简单的开始实例:

import 'ol/ol.css';
import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

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

你还需要一个 index.html 文件来使用包。如下是一个简单的示例:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Using Parcel with OpenLayers</title>
    <style>
      #map {
        width: 400px;
        height: 250px;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script src="./index.js"></script>
  </body>
</html>

创建一个bundle

通过在package.json中增加两行,你可以引入命令npm run build和npm start,分别手动构建你的bundle并且观察变化。最终包含这两个额外命令“start”和“build”命令的package.json文件应该是这个样子:

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "parcel index.html",
    "build": "parcel build --public-url . index.html"
  },
  "author": "",
  "license": "ISC"
}

现在开始你的请求,在控制台中输入:

npm start

来检验你的请求,在你的浏览器中打开http://localhost:1234/。无论什么时候,只要你进行了修改,这个页面都会自动重新加载,来展示修改的结果。

注意,在OpenLayers代码包中,一个包含你的请求代码和请求所用到的所有依赖的JavaScript文件已经生成,它只涵盖了必需的组件。

如果想为你的请求生成一个产品bundle,只需要输入下列代码并复制dist/文件夹到你的开发服务器中即可:

npm run build

2.基本概念

Map

map(ol/Map)是 OpenLayers 的核心组件,它被渲染到 target 容器中(例如页面中一个容纳地图的 div 元素)。所有的地图属性都可以在创建的时候进行配置,或进行自定义,例如 setTarget()。

下面这行代码可以用来生成一个容纳地图的 div。

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

下面的 JavaScript 代码,使用上述的 div 元素的 id “Map”作为选择器,可以构造出一个地图并渲染给它。

import Map from 'ol/Map';

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

View

map 不会操控地图的中心、缩放等级和投影等内容,因为这些是 ol/View的属性。

import View from 'ol/View';

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

View同样有投影,它决定了center的坐标系和地图分辨率计算的单位。如果没有指定(例如上面的代码段),默认的投影方式就是墨卡托球形投影(EPSG:3857),单位:米。

zoom选项可以很方便的设置地图的分辨率。可用的缩放等级取决于 maxZoom(默认值:28),zoomFactor(默认值:2)和maxResolution(默认值通过投影适配在256×256px的瓦片的有效范围来计算)。从每像素的maxResolution作为 level 0,随后的缩放等级,通过将上一个缩放等级通过zoomFactor进行划分来计算,直到到达maxZoom。

Source

OpenLayers 使用ol/source/source子数据源为layer远程添加数据。有很多可用的免费或商业用途的瓦片服务例如 OpenStreetMap 或 Bing,WMS 或WMTS可以提供 OGC 资源,GeoJSON 或 KML 可以提供矢量数据转换服务。

import OSM from 'ol/source/OSM';

var osmSource = OSM();

Layer

一个 layer 是从一个 source 获取到数据的视觉化表现。OpenLayers 有四种基本类型的 layer:

  • ol/layer/Tile :渲染提供特定分辨率的缩放等级的以栅格形式展示瓦片图像的资源;
  • ol/layer/Image:渲染提供任意内容和分辨率的地图图片;
  • ol/layer/Vector:渲染客户端的矢量数据;
  • ol/layer/VectorTile:渲染以矢量瓦片形式提供的数据。
import TileLayer from 'ol/layer/Tile';

var osmLayer = new TileLayer({source: osmSource});
map.addLayer(osmLayer);

将他们放在一起

把上面的那些代码片段组合起来,就可以放进一个用于生产一个瓦片layer的 script 中:

import Map from 'ol/Map';
import View from 'ol/View';
import OSM from 'ol/source/OSM';
import TileLayer from 'ol/layer/Tile';

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

3.OpenLayers的一些背景

介绍

OpenLayers是一个高集成、功能丰富的组件库,用来展示和交互地图以及地理相关数据。

该库内置支持各种商业和免费的图像和矢量图源,以及最流行的开源和专有的矢量数据转换。通过OpenLayers的地图投影支持,数据可以在任何投影中使用。

公共API

使用OpenLayers需要ol npm包,它提供了官方支持的API的所有模块。

渲染和浏览器支持

默认情况下,OpenLayers 使用性能优化的 Canvas 渲染器。
OpenLayers可以在所有支持HTML和ECMAScript 5的现有浏览器上运行,包括谷歌、火狐、Safari和Edge。对于较早的浏览器和平台例如IE9以下的版本、安卓 4.X,polyfills,请求代码需要进行转译(例如使用Babel编译器) 并与requestAnimationFrame、Element.prototype.classList和URL的polyfills绑定。

组件和命名规则

OpenLayers使用驼峰命名法生成默认类名,而且会包含额外的常量和函数名:

import Map from 'ol/Map';
import View from 'ol/View';

以父类进行分组的class层级,被分别放在代码包的子文件夹中,例如 layer/。
为方便起见,这些也可以作为命名的方式,例如:

import {Map, View} from 'ol';
import {Tile, Vector} from 'ol/layer';

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

import {getUid} from 'ol';
import {fromLonLat} from 'ol/proj';

4.光栅二次投影

相比服务器传输,OpenLayers更擅长在不同的坐标系上展示来自WMS、WMTS、静态图像和许多其他来源的栅格数据。

如何使用?

API 的使用方法非常简单,只需要在 ol/view上设定合适的投影(例如:使用EMSG码):

import {Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import TileWMS from 'ol/source/TileWMS';

var 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 DATA SOURCE PROJECTION
        url: 'http://demo.boundlessgeo.com/geoserver/wms',
        params: {
          'LAYERS': 'ne:NE1_HR_LC_SR_W_DR'
        }
      })
    })
  ]
});

如果一个source(基于ol/source/TileImage 或 ol/source/Image)有一个投影与当前ol/view的投影不同,那么会在引擎下自动进行重新投影。

例子

自定义投影

使用自定义投影最简单的方法就是在项目中添加Proj4js库,然后用 Proj4 的属性进行相关定义,安装代码为:

npm install proj4

下面这个例子展示了英国国家网是如何定义的:

import proj4 from 'proj4';
import {get as getProjection, register} from 'ol/proj';

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);
var proj27700 = getProjection('EPSG:27700');
proj27700.setExtent([0, 0, 700000, 1300000]);

改变view投影

要切换用于显示地图的投影,你必须在OL/Map上设置一个新的OL/View,并在OL/Map上选择投影。

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

TileGrid和范围

当需要重新投影时,新的瓦片(在目标投影中)是在原瓦片的基础上创建的新瓦片。默认情况下,重新投影的瓦片网格用的是ol/tilegrid~getForProjection(projection) 的内部构造设置。投影应当包含上述配置以保证程序正常运行。

另外,也可以手动构建一个自定义的目标TileGrid,并在源实例上使用ol/source/TileImage~setTileGridForProjection(projection(projection, tilegrid)手动设置,当按设定进行重新投影时,会用到这个自定义的TileGrid,而不会创建一个新的默认值。在某些情况下, 在某些情况下,这可以用来优化性能(通过调整瓦片大小)或视觉质量(通过指定分辨率)。

工作原理

重新投影过程是基于三角形——目标栅格被划分成一定数量的三角形,并使用 ol/proj 功能对顶点进行转换(proj4js经常被用来自定义转换)。三角形内的像素的重新投影是大致是通过仿射进行变换的(通过画布2d环境的硬件加速渲染)。


image

这样一来,我们就可以在几乎所有硬件上(支持画布2d的情况下)支持proj4js(甚至是自定义的变换函数)的大范围的投影,而实际的变换计算次数相对较少。
重新投影的精度取决于三角形的个数。
再投射过程保留了从源头提供的光栅数据(PNG或GIF)的透明度,并且通过再投射产生的空隙和无数据像素会自动透明。

动态三角划分

上面的图片有一个明显的错误(尤其在边界处),这种错误多发于源图像(左:EPSG:27700)仅通过一定数量的三角形(右:EPSG:3857)划分进行转化时。这种误差可以通过增加三角形的个数来尽力减小。
由于有些变换需要更精确的三角网络,因此,动态三角网的动态变换过程会自动测量重射误差,并迭代细分,以满足特定的误差阈值。


image

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

先进技术

三角形精密度阈值

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

按范围限制重新投影地图的可见度

重新投影使用的算法刚好相反(从视觉投影到数据投影),对于某些坐标系而言,这样会导致同一个地图上出现重复数据。例如,当将瑞士的地图从EPSG:21781 向 EPSG:3857进行重新投影时,它会展示两次:一次是在欧洲正确的位置。但是在地球的另一边,新西兰附近的太平洋也会出现一次。

image
尽管这种反向转变行为在数学上是可行的,但是用户并不想看到同一layer在不同地方重复出现。一个可能的一般解决方案是计算每个顶点的正向变换--但这将大大降低性能(尤其是对于计算成本较高的变换)。
因此在进行视觉投影时,推荐在 ol.layer.Tile 中界定一个合适的可视范围。在重新投影示例中演示了如何设置限制。

分辨率计算

当加载请求的瓦片地图资源时,需要计算理想的分辨率。ol/reproj~calculateSourceResolution(sourceProj, targetProj, targetCenter, targetResolution)函数的用处是在进行投影时计算最理想的值以使地图尽量达到1:1的像素比例,接着才能从资源中选取最合适的缩放等级。
然而,通篇都使用同一个缩放等级是不现实的,不同投影下,不同地区的分辨率有非常显著的区别(例如,EPSG:3857 和 EPSG:4326坐标系下的两极地区),并且在所有缩放等级下强制使用单一的分辨率会导致一些瓦片地图按比例放大/缩小,可能需要庞大数量的瓦片地图资源进行加载。因此应该分别为每一个重新投影的瓦片地图单独计算分辨率映射(在瓦片的中间范围)。

相关文章

网友评论

      本文标题:02 教程

      本文链接:https://www.haomeiwen.com/subject/byxjwhtx.html