GIS

OpenLayers Layer是什么

了解OpenLayers中Layer图层的基本概念、常见类型、Layer与Map、Source、Feature之间的关系,以及TileLayer、VectorLayer、ImageLayer和VectorTileLayer的使用场景。

阅读约 136 分钟

OpenLayers Layer是什么

Layer(图层)是OpenLayers地图中用于组织和显示地图数据的核心对象。

简单来说:

Layer决定地图上“显示哪一类数据”。

例如一个地图可以包含:

Map
├── 底图
├── 道路
├── 河流
├── 建筑物
├── 行政区
└── POI

这些内容通常可以分别放在不同的Layer中。

例如:

Map
│
├── TileLayer
│   └── 底图
│
├── VectorLayer
│   └── 道路
│
├── VectorLayer
│   └── 行政区
│
└── VectorLayer
    └── POI

因此可以把Layer理解为:

地图内容的组织和显示单元。

Layer在OpenLayers中的位置

OpenLayers最重要的数据结构之一是:

Map
 ↓
Layer
 ↓
Source
 ↓
Feature
 ↓
Geometry

例如:

Map
│
└── VectorLayer
      │
      └── VectorSource
            │
            ├── Feature
            │    └── Point
            │
            ├── Feature
            │    └── LineString
            │
            └── Feature
                 └── Polygon

其中:

Map
 ↓
管理整个地图

Layer
 ↓
组织和显示图层

Source
 ↓
提供图层数据

Feature
 ↓
空间要素

Geometry
 ↓
空间形状

为什么需要Layer

假设一个城市地图中有:

道路
建筑物
河流
行政区
POI

如果所有数据都直接放到Map中,管理会非常困难。

因此可以拆成:

Map
│
├── 道路Layer
├── 建筑Layer
├── 河流Layer
├── 行政区Layer
└── POI Layer

这样就可以单独控制每个图层。

例如:

道路Layer
├── 显示/隐藏
├── 透明度
├── 层级
└── 样式

建筑Layer
├── 显示/隐藏
├── 透明度
├── 层级
└── 样式

Layer的基本创建

OpenLayers提供不同类型的Layer。

例如:

import TileLayer from 'ol/layer/Tile.js'

创建:

const layer = new TileLayer({
  source
})

然后添加到Map:

map.addLayer(layer)

基本流程:

创建Layer
    ↓
配置Source
    ↓
添加到Map
    ↓
地图显示

Layer与Source的关系

Layer通常不会直接保存完整的GIS数据。

它主要通过Source获取数据。

例如:

VectorLayer
    ↓
VectorSource
    ↓
Feature[]

代码:

const source = new VectorSource({
  features
})

const layer = new VectorLayer({
  source
})

可以理解为:

Layer
 ↓
负责显示

Source
 ↓
负责数据

这是OpenLayers中非常重要的设计。

Layer常见类型

OpenLayers中常见的Layer包括:

TileLayer
ImageLayer
VectorLayer
VectorTileLayer
WebGLTile

不同Layer适合不同的数据。

Layer主要用途
TileLayer瓦片地图
ImageLayer图片地图
VectorLayer普通矢量数据
VectorTileLayer矢量瓦片
WebGLTileWebGL栅格瓦片

其中最常使用的是:

TileLayer
VectorLayer

TileLayer

TileLayer主要用于显示瓦片数据。

例如:

import TileLayer from 'ol/layer/Tile.js'
import OSM from 'ol/source/OSM.js'

const layer = new TileLayer({
  source: new OSM()
})

map.addLayer(layer)

结构:

TileLayer
    ↓
OSM
    ↓
地图瓦片

常用于:

  • OSM地图
  • XYZ瓦片
  • WMTS
  • 其他瓦片服务

TileLayer的特点

TileLayer不是直接显示一个完整的大地图图片。

它通常将地图切分成大量瓦片:

┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┴───┴───┘

浏览器只加载当前视野需要的瓦片。

因此非常适合:

大范围地图
在线底图
道路地图
卫星影像

VectorLayer

VectorLayer用于显示普通矢量数据。

例如:

import VectorLayer from 'ol/layer/Vector.js'
import VectorSource from 'ol/source/Vector.js'

const source = new VectorSource()

const layer = new VectorLayer({
  source
})

map.addLayer(layer)

结构:

VectorLayer
    ↓
VectorSource
    ↓
Feature
    ↓
Geometry

VectorLayer可以显示:

Point
LineString
Polygon
MultiPoint
MultiLineString
MultiPolygon

VectorLayer适合什么

VectorLayer非常适合业务数据。

例如:

POI
道路
行政区
建筑物
设备
车辆
管线
轨迹
电子围栏

例如:

设备Layer
├── 设备Feature
├── 设备Feature
└── 设备Feature

每个Feature可以包含:

Geometry
+
Properties

例如:

设备Feature
├── Point
├── name
├── status
└── deviceId

VectorTileLayer

VectorTileLayer用于显示矢量瓦片。

例如:

VectorTileLayer
    ↓
VectorTileSource
    ↓
MVT

常见格式:

MVT
PBF

与普通VectorLayer相比:

VectorLayer
 ↓
大量Feature

VectorTileLayer
 ↓
大量矢量瓦片

VectorTileLayer更适合:

  • 全国地图
  • 城市地图
  • 大规模道路
  • 大量建筑物
  • 高性能地图

ImageLayer

ImageLayer主要用于显示单张地图影像或图片数据。

例如:

ImageLayer
    ↓
ImageSource

适合:

  • WMS图片
  • 服务端生成地图
  • 单张地图影像
  • 专题地图

与TileLayer相比:

TileLayer
 ↓
很多瓦片

ImageLayer
 ↓
一张或少量图片

WebGLTile

WebGLTile主要用于使用WebGL渲染栅格瓦片。

适合处理:

栅格数据
影像
DEM
科学数据

它可以利用GPU提高大规模栅格数据的显示性能。

Layer的visible

Layer可以控制是否显示。

例如:

layer.setVisible(false)

隐藏图层:

visible = false

显示:

layer.setVisible(true)

也可以初始化:

const layer = new VectorLayer({
  source,
  visible: false
})

这样图层默认不显示。

常用于:

图层开关
图层控制面板
专题图切换
业务图层显示控制

Layer的opacity

opacity用于控制透明度。

例如:

layer.setOpacity(0.5)

其中:

1
 ↓
完全不透明

0.5
 ↓
半透明

0
 ↓
完全透明

例如卫星影像:

imageryLayer.setOpacity(0.7)

可以让下面的矢量图层更加容易观察。

Layer的zIndex

zIndex用于控制图层的显示顺序。

例如:

roadLayer.setZIndex(10)
poiLayer.setZIndex(20)

那么:

POI
 ↓
zIndex 20

道路
 ↓
zIndex 10

通常数值越大的图层显示层级越高。

可以理解为:

zIndex
 ↑
 │
POI
道路
行政区
底图

Layer的minZoom

可以限制图层在哪些缩放级别显示。

例如:

const layer = new VectorLayer({
  source,
  minZoom: 10
})

表示在较小缩放级别时不显示该图层。

适合:

全国范围
 ↓
不显示POI

城市范围
 ↓
显示POI

街道范围
 ↓
显示详细建筑

Layer的maxZoom

也可以限制最大缩放级别。

例如:

const layer = new VectorLayer({
  source,
  maxZoom: 18
})

这样超过指定缩放级别后图层就不会继续显示。

因此:

minZoom
 ↓
最小显示缩放级别

maxZoom
 ↓
最大显示缩放级别

Layer的extent

extent可以限制Layer显示的空间范围。

例如:

const layer = new VectorLayer({
  source,
  extent: [
    12900000,
    4800000,
    13000000,
    4900000
  ]
})

可以理解为:

只有进入指定空间范围
        ↓
Layer才参与显示

适合:

  • 区域专题图
  • 分区数据
  • 局部业务图层

Layer的className

可以给Layer设置CSS类名。

例如:

const layer = new VectorLayer({
  source,
  className: 'road-layer'
})

这样可以方便进行特定的DOM相关控制。

不过需要注意:

OpenLayers的主要地图渲染并不是依赖普通HTML DOM元素完成的。

因此Layer样式控制主要还是通过OpenLayers自身的渲染和Style机制。

Layer的properties

Layer也可以保存自定义属性。

例如:

const layer = new VectorLayer({
  source,
  properties: {
    name: '道路',
    type: 'road',
    category: 'transport'
  }
})

获取:

layer.get('name')

得到:

道路

这对于构建图层管理系统非常有用。

例如:

Layer
├── name
├── type
├── category
└── source

Layer的Source

Layer最重要的配置之一就是Source。

例如:

const layer = new VectorLayer({
  source
})

可以动态获取:

const source = layer.getSource()

然后操作Source:

source.addFeature(feature)

因此:

Layer
 ↓
getSource()
 ↓
Source

Layer动态添加

地图创建后可以动态添加Layer。

map.addLayer(layer)

例如:

map.addLayer(roadLayer)
map.addLayer(buildingLayer)
map.addLayer(poiLayer)

最终:

Map
├── roadLayer
├── buildingLayer
└── poiLayer

Layer动态删除

可以使用:

map.removeLayer(layer)

例如:

map.removeLayer(poiLayer)

这样POI图层就会从地图中移除。

注意:

removeLayer只是将Layer从Map的图层集合中移除,并不等于删除Layer对象本身。

获取所有Layer

可以:

const layers = map.getLayers()

然后:

layers.forEach(layer => {
  console.log(layer)
})

可以用于:

  • 图层管理
  • 图层排序
  • 图层批量控制
  • 图层面板

LayerGroup

当Layer数量较多时,可以使用LayerGroup进行组织。

结构:

Map
│
├── 底图
│
└── LayerGroup
    ├── 道路
    ├── 建筑
    └── POI

例如:

import LayerGroup from 'ol/layer/Group.js'

const group = new LayerGroup({
  layers: [
    roadLayer,
    buildingLayer,
    poiLayer
  ]
})

map.addLayer(group)

这样就可以把多个Layer作为一个整体管理。

LayerGroup的作用

例如:

交通图层组
├── 道路
├── 铁路
└── 地铁

可以整体:

显示
隐藏
管理

例如:

group.setVisible(false)

整个交通图层组都会隐藏。

Layer与LayerGroup

可以理解为:

Layer
 ↓
单个图层

LayerGroup
 ↓
多个图层的集合

例如:

Map
│
├── Base Layer
│
├── Transportation Group
│   ├── Road Layer
│   ├── Railway Layer
│   └── Subway Layer
│
└── POI Layer

这种结构非常适合复杂WebGIS应用。

Layer的顺序

多个Layer叠加时需要考虑显示顺序。

例如:

最上层
 ↓
POI
道路
行政区
卫星影像
底图
 ↓
最下层

可以使用zIndex控制。

例如:

baseLayer.setZIndex(0)
boundaryLayer.setZIndex(10)
roadLayer.setZIndex(20)
poiLayer.setZIndex(30)

最终:

POI
 ↓ 30

道路
 ↓ 20

行政区
 ↓ 10

底图
 ↓ 0

Layer与Feature的区别

Layer和Feature非常容易混淆。

它们负责的事情不同。

Layer
 ↓
组织一组数据

Feature
 ↓
表示一个具体空间要素

例如:

道路Layer
├── Feature:道路1
├── Feature:道路2
└── Feature:道路3

每个Feature都有自己的Geometry:

道路Feature
 ↓
LineString

所以:

Layer
 ↓
Source
 ↓
Feature[]
 ↓
Geometry

Layer与Geometry的区别

Geometry描述形状:

Point
LineString
Polygon

Layer描述显示的数据集合。

例如:

POI Layer
 ↓
Feature
 ↓
Point

因此不能简单认为:

Layer = Geometry

正确关系是:

Layer
 ↓
Source
 ↓
Feature
 ↓
Geometry

Layer与GeoJSON的关系

GeoJSON是一种数据格式。

Layer是OpenLayers中的地图图层对象。

典型流程:

GeoJSON
 ↓
GeoJSON Format
 ↓
Feature[]
 ↓
VectorSource
 ↓
VectorLayer
 ↓
Map

例如:

const features = new GeoJSON().readFeatures(data)

const source = new VectorSource({
  features
})

const layer = new VectorLayer({
  source
})

map.addLayer(layer)

因此:

GeoJSON不是Layer,而是可以转换成Feature后放入VectorLayer的数据格式。

Layer与WMS的关系

WMS是一种地图服务。

OpenLayers可以通过对应Source加载WMS。

典型结构:

WMS
 ↓
TileWMS / ImageWMS
 ↓
TileLayer / ImageLayer
 ↓
Map

例如:

TileLayer
 ↓
TileWMS
 ↓
WMS服务

Layer与XYZ的关系

XYZ主要是一种瓦片访问方式。

结构:

XYZ
 ↓
XYZ Source
 ↓
TileLayer
 ↓
Map

例如:

import XYZ from 'ol/source/XYZ.js'

const source = new XYZ({
  url: 'https://example.com/{z}/{x}/{y}.png'
})

const layer = new TileLayer({
  source
})

因此:

XYZ
 ↓
Source

TileLayer
 ↓
显示瓦片

Layer与WMTS的关系

WMTS是标准瓦片地图服务。

结构:

WMTS
 ↓
WMTS Source
 ↓
TileLayer
 ↓
Map

适合加载:

  • 标准地图服务
  • 专题地图
  • 影像地图
  • 地形地图

Layer与Vector Tile的关系

Vector Tile主要使用矢量瓦片。

结构:

MVT
 ↓
VectorTileSource
 ↓
VectorTileLayer
 ↓
Map

适合大规模矢量地图。

例如:

全国道路
 ↓
大量Vector Tile
 ↓
VectorTileLayer
 ↓
地图

Layer样式

不同Layer的样式方式有所不同。

VectorLayer通常使用Style。

例如:

const layer = new VectorLayer({
  source,
  style: feature => {
    return style
  }
})

可以根据Feature属性动态设置样式。

例如:

status = online
 ↓
绿色

status = offline
 ↓
红色

这在业务GIS中非常常见。

根据Feature设置样式

例如:

const layer = new VectorLayer({
  source,

  style: feature => {
    const status = feature.get('status')

    if (status === 'online') {
      return onlineStyle
    }

    return offlineStyle
  }
})

这样一个Layer中的不同Feature就可以显示不同效果。

Layer与性能

Layer并不是越多越好。

例如:

Map
├── Layer 1
├── Layer 2
├── Layer 3
├── ...
└── Layer 1000

过多Layer会增加管理和渲染复杂度。

设计地图时应该合理组织:

底图
 ↓
专题图层
 ↓
业务图层
 ↓
交互图层

对于大量数据,还需要考虑:

Vector Tile
数据分级
空间索引
按缩放级别加载
按范围加载
WebGL

Layer常见应用结构

一个实际的城市GIS系统可能是:

Map
│
├── BaseMap
│
├── AdministrativeLayer
│
├── RoadLayer
│
├── BuildingLayer
│
├── RiverLayer
│
├── POILayer
│
├── DeviceLayer
│
└── InteractionLayer

其中:

BaseMap
 ↓
底图

AdministrativeLayer
 ↓
行政区

RoadLayer
 ↓
道路

BuildingLayer
 ↓
建筑

DeviceLayer
 ↓
业务设备

InteractionLayer
 ↓
选择、高亮、绘制

推荐的Layer设计

实际项目中,可以按照业务类型组织:

Map
│
├── Base
│   └── BaseLayer
│
├── GIS
│   ├── BoundaryLayer
│   ├── RoadLayer
│   ├── RiverLayer
│   └── BuildingLayer
│
├── Business
│   ├── DeviceLayer
│   ├── VehicleLayer
│   └── POILayer
│
└── Interaction
    ├── SelectionLayer
    ├── DrawLayer
    └── HighlightLayer

这种结构比把所有Feature都放到一个VectorLayer中更加容易维护。

Layer核心关系

OpenLayers中Layer最重要的关系可以总结为:

Map
 ↓
Layer
 ↓
Source
 ↓
Feature
 ↓
Geometry

不同数据对应不同Layer:

瓦片
 ↓
TileLayer

普通矢量
 ↓
VectorLayer

矢量瓦片
 ↓
VectorTileLayer

图片
 ↓
ImageLayer

栅格瓦片
 ↓
WebGLTile

Layer核心属性

常用Layer属性包括:

source
visible
opacity
zIndex
minZoom
maxZoom
extent
className
properties

其中最常使用的是:

source
visible
opacity
zIndex

Layer常用操作

添加

map.addLayer(layer)

删除

map.removeLayer(layer)

获取Source

layer.getSource()

显示

layer.setVisible(true)

隐藏

layer.setVisible(false)

设置透明度

layer.setOpacity(0.5)

设置层级

layer.setZIndex(10)

设置属性

layer.set('name', '道路')

Layer知识结构

可以用下面的结构理解OpenLayers Layer:

Layer
│
├── TileLayer
│   └── TileSource
│       ├── OSM
│       ├── XYZ
│       └── WMTS
│
├── ImageLayer
│   └── ImageSource
│       └── WMS
│
├── VectorLayer
│   └── VectorSource
│       └── Feature
│           └── Geometry
│
├── VectorTileLayer
│   └── VectorTileSource
│       └── MVT
│
└── WebGLTile
    └── TileSource

总结

Layer是OpenLayers地图中的核心组成部分,主要负责组织和显示地图数据。

最重要的关系是:

Map
 ↓
Layer
 ↓
Source
 ↓
Feature
 ↓
Geometry

常见Layer包括:

TileLayer
VectorLayer
ImageLayer
VectorTileLayer
WebGLTile

可以记住:

TileLayer主要显示瓦片,VectorLayer主要显示普通矢量数据,ImageLayer主要显示图片地图,VectorTileLayer主要显示矢量瓦片,而Layer通过Source获取数据并最终显示在Map中。

掌握Layer之后,下一步可以继续学习OpenLayers中的Source,理解VectorSourceXYZWMTSTileWMS以及ImageWMS等数据源是如何与Layer配合工作的。

🧰

相关工具

使用 IYATools 在线工具快速处理 GIS 数据