OpenLayers Map是什么
Map是OpenLayers中最核心的对象。
它代表一个完整的Web地图实例,负责组织:
- 地图图层
- 地图视图
- 地图控件
- 地图交互
- 地图事件
- 地图渲染
- 地图目标容器
简单来说:
Map就是OpenLayers地图应用的核心容器。
例如:
Map
├── View
├── Layers
├── Controls
├── Interactions
└── Target
一个完整的OpenLayers地图通常从创建Map开始。
Map的基本结构
OpenLayers中的核心关系可以理解为:
Map
│
├── View
│
├── Layer
│ └── Source
│ └── Feature
│ └── Geometry
│
├── Interaction
│
└── Control
其中:
Map
↓
管理整个地图
View
↓
决定地图看哪里、缩放多少
Layer
↓
决定显示哪些内容
Source
↓
提供地图数据
Feature
↓
表示空间要素
Geometry
↓
表示空间形状
Interaction
↓
处理用户操作
Control
↓
提供地图控件
创建Map
首先引入Map:
import Map from 'ol/Map.js'
然后创建:
const map = new Map({
target: 'map'
})
这里的:
target
表示地图需要挂载到哪个HTML元素。
例如:
<div id="map"></div>
然后:
const map = new Map({
target: 'map'
})
这样OpenLayers就会将地图渲染到:
#map
这个元素中。
Map的target
target用于指定地图容器。
例如:
const map = new Map({
target: document.getElementById('map')
})
也可以直接使用元素ID:
const map = new Map({
target: 'map'
})
对应:
<div id="map"></div>
因此:
HTML
↓
<div id="map">
↓
OpenLayers Map
地图容器必须有尺寸
这是OpenLayers开发中非常常见的问题。
例如:
<div id="map"></div>
如果没有设置高度:
#map {
height: 0;
}
地图可能不会正常显示。
通常需要:
#map {
width: 100%;
height: 500px;
}
或者:
html,
body,
#map {
width: 100%;
height: 100%;
}
因此地图显示异常时,除了检查JavaScript,也需要检查地图容器尺寸。
Map的View
Map最重要的配置之一是View。
例如:
import View from 'ol/View.js'
const view = new View({
center: [12950000, 4850000],
zoom: 10
})
然后:
const map = new Map({
target: 'map',
view
})
结构:
Map
↓
View
View负责控制:
- 中心点
- 缩放
- 旋转
- 投影
- 分辨率
可以理解为:
View决定用户从哪里、以什么缩放级别观察地图。
Map的center
center表示地图中心坐标。
例如:
const view = new View({
center: [12950000, 4850000],
zoom: 10
})
这里的坐标通常是:
X = 12950000
Y = 4850000
具体含义取决于View使用的投影。
如果使用:
EPSG:3857
则通常使用Web Mercator投影坐标。
Map的zoom
zoom表示地图缩放级别。
例如:
const view = new View({
center: [12950000, 4850000],
zoom: 10
})
通常:
zoom较小
↓
显示范围较大
zoom较大
↓
显示范围较小
例如:
zoom 3
↓
大范围地图
zoom 10
↓
城市范围
zoom 16
↓
街道和建筑
具体显示范围取决于地图投影和分辨率配置。
Map的projection
投影通常配置在View中:
const view = new View({
projection: 'EPSG:3857'
})
常见:
EPSG:4326
EPSG:3857
例如:
const view = new View({
projection: 'EPSG:3857',
center: [12950000, 4850000],
zoom: 10
})
可以理解为:
Map
↓
View
↓
Projection
↓
决定地图坐标体系
一个完整Map
一个简单的OpenLayers地图通常如下:
import Map from 'ol/Map.js'
import View from 'ol/View.js'
import TileLayer from 'ol/layer/Tile.js'
import OSM from 'ol/source/OSM.js'
const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
})
],
view: new View({
center: [12950000, 4850000],
zoom: 10
})
})
完整结构:
Map
│
├── TileLayer
│ └── OSM
│
└── View
├── center
└── zoom
Map与Layer
Map负责管理Layer。
例如:
map.addLayer(layer)
地图可以拥有多个Layer:
Map
├── BaseLayer
├── RoadLayer
├── BuildingLayer
├── RiverLayer
└── POILayer
获取Layer:
const layers = map.getLayers()
删除Layer:
map.removeLayer(layer)
因此:
Map
↓
管理Layer集合
Map与Source
Map通常不会直接管理Source。
它们之间一般是:
Map
↓
Layer
↓
Source
例如:
Map
↓
VectorLayer
↓
VectorSource
所以如果需要操作Feature,通常需要:
const source = vectorLayer.getSource()
const features = source.getFeatures()
而不是直接从Map获取Feature。
Map与Feature
Map本身不直接表示Feature。
典型关系:
Map
↓
VectorLayer
↓
VectorSource
↓
Feature
↓
Geometry
例如:
Map
└── VectorLayer
└── VectorSource
├── Feature
│ └── Point
├── Feature
│ └── LineString
└── Feature
└── Polygon
Map与Interaction
Interaction负责处理用户与地图之间的交互。
常见Interaction:
DragPan
MouseWheelZoom
DoubleClickZoom
DragZoom
Select
Draw
Modify
Translate
例如添加Draw:
import Draw from 'ol/interaction/Draw.js'
const draw = new Draw({
source,
type: 'Point'
})
map.addInteraction(draw)
结构:
Map
↓
Interaction
↓
用户操作
Map与Control
Control用于提供地图控件。
常见Control:
Zoom
Rotate
FullScreen
ScaleLine
MousePosition
OverviewMap
ZoomSlider
例如:
import ScaleLine from 'ol/control/ScaleLine.js'
const scaleLine = new ScaleLine()
map.addControl(scaleLine)
这样地图上就会出现比例尺。
Map与事件
Map提供大量事件。
例如:
click
singleclick
dblclick
pointermove
pointerdrag
movestart
moveend
最常用的是:
map.on('singleclick', event => {
console.log(event.coordinate)
})
这里:
event.coordinate
表示地图坐标。
singleclick
singleclick用于监听地图单击。
例如:
map.on('singleclick', event => {
console.log('点击坐标:', event.coordinate)
})
可以用于:
- 查询地图位置
- 点击Feature
- 获取坐标
- 弹出信息窗口
click与singleclick
OpenLayers中经常使用:
singleclick
来处理地图单击。
例如:
map.on('singleclick', event => {
console.log(event.coordinate)
})
如果需要区分双击等交互行为,应根据具体业务选择合适的事件。
pointermove
pointermove用于监听鼠标移动。
例如:
map.on('pointermove', event => {
console.log(event.coordinate)
})
常用于:
- 鼠标位置坐标
- Feature悬停
- 鼠标样式切换
- 高亮Feature
例如:
map.on('pointermove', event => {
const feature = map.forEachFeatureAtPixel(
event.pixel,
feature => feature
)
if (feature) {
console.log('悬停Feature:', feature)
}
})
movestart
当地图开始移动时触发:
map.on('movestart', () => {
console.log('地图开始移动')
})
例如:
用户拖动地图
↓
movestart
↓
地图移动
moveend
当地图移动完成后触发:
map.on('moveend', () => {
console.log('地图移动结束')
})
常用于:
- 获取当前地图范围
- 根据地图范围加载数据
- 更新业务数据
- 更新URL参数
例如:
map.on('moveend', () => {
const extent = map.getView().calculateExtent(
map.getSize()
)
console.log(extent)
})
获取View
可以通过Map获取View:
const view = map.getView()
然后:
view.getCenter()
view.getZoom()
例如:
const center = map.getView().getCenter()
const zoom = map.getView().getZoom()
设置地图中心
可以:
map.getView().setCenter([
12950000,
4850000
])
地图就会移动到指定位置。
设置地图缩放
可以:
map.getView().setZoom(12)
例如:
当前 zoom = 10
↓
setZoom(12)
↓
放大地图
动画移动
OpenLayers可以通过View动画改变地图位置。
例如:
map.getView().animate({
center: [12950000, 4850000],
zoom: 12,
duration: 1000
})
这样地图会平滑移动到指定位置。
fit
fit是OpenLayers中非常重要的地图操作。
例如有一个Feature:
const extent = feature.getGeometry().getExtent()
map.getView().fit(extent)
地图会自动调整视图,使Geometry进入当前地图范围。
常用于:
- 定位Feature
- 缩放到行政区
- 缩放到道路
- 缩放到GeoJSON
- 显示查询结果
例如:
Feature
↓
Geometry
↓
Extent
↓
View.fit()
↓
地图自动定位
Map的size
可以通过:
const size = map.getSize()
获得地图尺寸。
例如:
[
1200,
800
]
表示地图容器大约为:
宽度 = 1200
高度 = 800
Map的pixel与coordinate
OpenLayers中经常需要在:
Pixel
和:
Coordinate
之间转换。
例如:
Pixel
↓
屏幕位置
Coordinate
↓
地图坐标
获取像素:
event.pixel
获取地图坐标:
event.coordinate
Pixel转Coordinate
可以使用:
map.getCoordinateFromPixel(pixel)
例如:
const coordinate = map.getCoordinateFromPixel([
500,
300
])
得到地图坐标。
Coordinate转Pixel
反过来:
map.getPixelFromCoordinate(coordinate)
例如:
const pixel = map.getPixelFromCoordinate([
12950000,
4850000
])
这样可以获得对应的屏幕像素位置。
Feature点击查询
Map提供:
map.forEachFeatureAtPixel()
例如:
map.on('singleclick', event => {
map.forEachFeatureAtPixel(
event.pixel,
feature => {
console.log(feature)
}
)
})
流程:
用户点击
↓
Pixel
↓
Map
↓
forEachFeatureAtPixel
↓
Feature
这是OpenLayers中非常常见的Feature查询方式。
获取地图Extent
地图当前显示范围可以通过View计算:
const extent = map
.getView()
.calculateExtent(map.getSize())
得到:
[minX, minY, maxX, maxY]
例如:
[
12800000,
4700000,
13100000,
5000000
]
可以用于:
- 空间查询
- 按范围加载数据
- 服务请求
- 地图范围统计
Map的渲染
OpenLayers会根据:
View
Layer
Source
Feature
Geometry
进行地图渲染。
可以理解为:
View
↓
确定当前显示范围
↓
Layer
↓
确定需要显示的内容
↓
Source
↓
提供数据
↓
Feature
↓
空间对象
↓
Geometry
↓
几何形状
↓
Renderer
↓
屏幕地图
Map的渲染方式
OpenLayers支持多种渲染方式,例如:
Canvas
WebGL
普通VectorLayer通常使用Canvas渲染。
在大规模数据场景下,也可以根据数据类型选择WebGL相关Layer。
因此实际项目中需要根据数据规模选择合适的渲染方式。
Map的渲染更新
当Layer、Source或Feature发生变化时,OpenLayers通常会自动触发重新渲染。
某些情况下也可以:
map.render()
主动请求重新渲染。
例如:
map.render()
可以用于某些自定义渲染场景。
Map的控件管理
获取Controls:
const controls = map.getControls()
添加:
map.addControl(control)
删除:
map.removeControl(control)
因此:
Map
↓
Controls
可以统一管理地图上的控制组件。
Map的交互管理
获取Interactions:
const interactions = map.getInteractions()
添加:
map.addInteraction(interaction)
删除:
map.removeInteraction(interaction)
例如:
map.addInteraction(draw)
Map的Layer管理
获取Layers:
const layers = map.getLayers()
添加:
map.addLayer(layer)
删除:
map.removeLayer(layer)
因此Map实际上是整个地图对象的管理中心。
Map的核心方法
开发OpenLayers时,经常使用:
getView()
getLayers()
addLayer()
removeLayer()
getControls()
addControl()
removeControl()
getInteractions()
addInteraction()
removeInteraction()
getSize()
getPixelFromCoordinate()
getCoordinateFromPixel()
forEachFeatureAtPixel()
render()
这些方法基本覆盖了大量日常地图开发需求。
Map的完整结构
一个比较完整的OpenLayers Map可以理解为:
Map
│
├── Target
│ └── HTML地图容器
│
├── View
│ ├── Center
│ ├── Zoom
│ ├── Rotation
│ ├── Projection
│ └── Resolution
│
├── Layers
│ ├── TileLayer
│ │ └── TileSource
│ │
│ ├── VectorLayer
│ │ └── VectorSource
│ │ └── Feature
│ │ └── Geometry
│ │
│ └── VectorTileLayer
│ └── VectorTileSource
│
├── Interactions
│ ├── Select
│ ├── Draw
│ ├── Modify
│ └── DragPan
│
└── Controls
├── Zoom
├── ScaleLine
├── FullScreen
└── MousePosition
一个实际地图的结构
例如一个城市GIS系统:
Map
│
├── View
│
├── BaseMap
│ └── TileLayer
│
├── GIS Layer
│ ├── 行政区
│ ├── 道路
│ ├── 河流
│ └── 建筑物
│
├── Business Layer
│ ├── 设备
│ ├── 车辆
│ └── POI
│
├── Interaction
│ ├── Select
│ ├── Draw
│ └── Modify
│
└── Controls
├── Zoom
└── ScaleLine
Map与Layer的关系
可以记住:
Map
↓
管理Layer
Layer负责:
显示什么
Map负责:
在哪里显示
如何交互
如何管理
Map与View的关系
可以记住:
Map
↓
View
View决定:
中心在哪里
缩放多少
旋转多少
使用什么投影
例如:
Map
↓
View
├── center
├── zoom
├── rotation
└── projection
Map与Interaction的关系
可以记住:
Map
↓
Interaction
↓
用户操作
例如:
用户绘制
↓
Draw
用户选择
↓
Select
用户编辑
↓
Modify
用户拖动地图
↓
DragPan
Map与Control的关系
可以记住:
Map
↓
Control
↓
地图操作组件
例如:
Zoom
↓
缩放按钮
ScaleLine
↓
比例尺
FullScreen
↓
全屏按钮
Map初始化流程
一个典型OpenLayers项目可以按照下面流程初始化:
创建HTML容器
↓
创建Layer
↓
创建Source
↓
加载数据
↓
创建View
↓
创建Map
↓
添加Controls
↓
添加Interactions
↓
监听地图事件
最终:
HTML
↓
Map
↓
View + Layer + Interaction + Control
↓
WebGIS地图
Vue中使用Map
在Vue项目中,通常需要在组件挂载完成后创建Map。
例如:
import { onMounted, onBeforeUnmount } from 'vue'
let map
onMounted(() => {
map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
})
],
view: new View({
center: [12950000, 4850000],
zoom: 10
})
})
})
模板:
<template>
<div id="map"></div>
</template>
组件销毁时可以解除地图与容器的关联:
onBeforeUnmount(() => {
map?.setTarget(undefined)
})
这样可以避免组件销毁后地图实例继续占用DOM容器。
Map开发中的常见问题
地图不显示
首先检查:
1. target是否正确
2. HTML元素是否存在
3. 地图容器是否有高度
4. View是否正确
5. Layer是否正确
6. Source是否正常
地图位置错误
重点检查:
数据坐标系
View坐标系
数据Projection
例如:
EPSG:4326
↓
EPSG:3857
是否正确转换。
Feature不显示
检查:
Feature
↓
VectorSource
↓
VectorLayer
↓
Map
是否完整。
Layer不显示
检查:
layer.getVisible()
以及:
layer.getOpacity()
layer.getZIndex()
还需要检查Layer的Zoom和Extent限制。
Map知识结构
可以用下面的结构记忆:
OpenLayers Map
│
├── Target
│
├── View
│ ├── Center
│ ├── Zoom
│ ├── Rotation
│ ├── Projection
│ └── Resolution
│
├── Layers
│ ├── TileLayer
│ ├── VectorLayer
│ ├── ImageLayer
│ └── VectorTileLayer
│
├── Interactions
│ ├── Select
│ ├── Draw
│ ├── Modify
│ └── DragPan
│
├── Controls
│ ├── Zoom
│ ├── ScaleLine
│ └── FullScreen
│
└── Events
├── singleclick
├── pointermove
├── movestart
└── moveend
总结
Map是OpenLayers中最核心的对象,它代表一个完整的WebGIS地图实例。
最重要的关系是:
Map
│
├── View
├── Layer
├── Interaction
├── Control
└── Event
其中:
Map
↓
整个地图
View
↓
控制地图视角
Layer
↓
组织地图内容
Source
↓
提供地图数据
Feature
↓
表示空间要素
Geometry
↓
表示空间形状
Interaction
↓
处理用户交互
Control
↓
提供地图控件
可以记住:
Map是OpenLayers地图的核心管理对象,View决定怎么看地图,Layer决定显示什么,Source提供数据,Feature表示空间要素,Geometry表示空间形状,Interaction负责用户操作,Control负责地图控件。
理解Map之后,OpenLayers最核心的一条知识链就是:
Map
↓
View
↓
Layer
↓
Source
↓
Feature
↓
Geometry
再结合:
Interaction
Control
Event
就基本构成了OpenLayers WebGIS开发的核心体系。
相关工具
使用 IYATools 在线工具快速处理 GIS 数据