笔记参考教程来源于B站UP主znlgis的视频合集:https://space.bilibili.com/161342702
,直播使用的源码地址:https://github.com/OpenGisToolbox。
Demo合集分为5大部分,分别是:基础环境搭建、项目搭建、GeoServer Rest API引入、OpenLayers API简介、图层树组织,这个教程合集主要是使用了前端内容,后端内容涉及较少。
该Demo功能需求为:基于GeoServer REST API,以地图展示和服务管理为核心,实现一张图的原型/示范,主要是实现地图展示(树状展示各种地图服务,并以地图形式展示)和服务管理(树状管理地图服务,包括添加、删除、修改、查看等基础操作)。该合集需要掌握的基础内容包括:HTML+CSS+JS基础、DOM基础、VUE3基础、Element Plus和OpenLayers、VUE3-OpenLayers等前端框架基础。
1 基础环境搭建
为了解决跨域问题,可以修改GeoServer配置或通过Nginx配置,UP主znlgis介绍了使用主流的Nginx。我在之前的学习笔记中,记录了如何在Ubuntu中安装配置GeoServer、Nginx、Postgis等,这里使用Docker Desktop直接在windows中安装。
1.1 Docker安装PostGIS、GeoServer、Nginx
使用Docker Desktop安装PostGIS、GeoServer、Nginx,可以通过Docker Desktop直接进行可视化操作,拉取后运行。
当然,安装PostGIS也可以参考官网等:https://hub.docker.com/r/postgis/postgis
,使用如下代码:
# 安装Postgis,拉取镜像
docker pull postgis/postgis
# 运行容器
docker run --name postgis \#容器名称-e POSTGRES_USER=postgres \# 数据库用户名-e POSTGRES_PASSWORD=postgres \#密码-e POSTGRES_DB=mydatabase \#创建的数据库-p 5432:5432 \#端口-v D:/Programs/DockerData/PostGIS:/var/lib/postgresql/data \#持久化数据,挂载到本地D:/Programs/DockerData/PostGIS文件夹-d postgis/postgis:latest#使用 postgis/postgis 镜像的最新版本(latest 标签)以后台模式(-d)运行容器
安装GeoServer如下,结合znlgis视频与参考网址:https://docs.geoserver.org/latest/en/user/installation/docker.html
,此外,在GeoServer安装过程中设置了容器间访问,安装完成后访问地址:http://localhost:8765/geoserver,确保能正确使用。
#拉取镜像,我这里拉取的稳定版本,不是最新版本
docker pull docke:r.osgeo.org/geoserver:2.26.x
#首次运行,初始化了默认的样例数据
docker run -p 8765:8080 --name geoserver\#由于端口冲突,修改了端口--link postgis:postgis \#将 GeoServer 容器链接到名为 postgis 的 PostGIS 容器-e SAMPLE_DATA=true \#启用示例数据-e GEOSERVER_ADMIN_PASSWORD=geoserver \# GeoServer 管理员密码-e GEOSERVER_DATA_DIR=/opt/geoserver_data/data_dir \#环境变量,GeoServer 数据目录-e GEOWEBCACHE_CACHE_DIR=/opt/geoserver_data/data_dir/gwc \#环境变量,GeoWebCache 缓存目录-v D:/Programs/DockerData/geoserver:/opt/geoserver_data \#持久化 GeoServer 数据-v D:/Programs/DockerData/geoserver/data_dir/gwc:/opt/geoserver_data/data_dir/gwc \#持久化 GeoWebCache 缓存数据-d docker.osgeo.org/geoserver:2.26.x #在后台运行容器,使用 GeoServer 的 2.26.x 版本镜像# 非首次运行,不用再启用样例数据
docker run --name geoserver -p 8765:8080 --link postgis:postgis -e GEOSERVER_ADMIN_PASSWORD=geoserver -e GEOSERVER_DATA_DIR=/opt/geoserver_data/data_dir -e GEOWEBCACHE_CACHE_DIR=/opt/geoserver_data/data_dir/gwc -v D:/Programs/DockerData/geoserver:/opt/geoserver_data -v D:/Programs/DockerData/geoserver/data_dir/gwc:/opt/geoserver_data/gwc -d docker.osgeo.org/geoserver:2.26.x
docker安装Nginx代码如下,首先拉取镜像;然后查看默认的 Nginx 配置文件内容,在要挂载的路径下,新建一个nginx.conf文件,并将输出的内容复制到该文件中;然后启动 Nginx 容器、挂载配置文件;在后续再修改配置文件。
#拉取镜像
docker pull nginx#查看默认的 Nginx 配置文件,--rm表示容器退出后自动删除,--entrypoint=cat指定容器启动时运行cat命令查看文件内容,使用 Nginx 镜像,查看特定文件路径。这个命令运行输出nginx.conf文件的内容。
docker run --rm --entrypoint=cat nginx /etc/nginx/nginx.conf#启动 Nginx 容器、挂载配置文件,这里的:ro表示以只读模式挂载,
docker run --name nginx -v D:/Programs/DockerData/nginx/nginx.conf:/etc/nginx/nginx.conf:ro -p 8080:80 -d nginx
此外,还需要安装vue、nvm和node.js,在先前其他内容的学习中已经做过相关的分享笔记,就不再赘述。
1.2 实验数据
原教程使用的样例数据来源于网站:https://www.poi86.com/,该网站数据存在一定的错误/误差,但完全可以用来搭建一个Demo;也可以使用其他数据。我这里下载了北京市水系数据,首先将该数据使用PostGIS导入数据库,然后使用QGIS生成了一个geoserver能够使用的样式文件,最后将postgis数据库连接到geoserver,设置样式并预览。
(1)postgis导入数据
我这里下载的北京市水系数据,将数据导入postgis数据库。由于使用的docker安装的postgis,可以先查看容器列表:docker ps
,接着进入某个docker容器,这里进入的postgis容器:docker exec -it postgis /bin/bash
,这里的exec
表示在运行的容器中执行的命令;-it
表示使用交互模式执行命令,并为容器分配伪终端;postgis
表示要进入的容器名称;/bin/bash
表示在容器中启动bash
。
由于导入数据需要使用GDAL包,首先查看GDAL是否安装:ogrinfo --version
或gdalinfo --version
,如果容器中没有GDAL,先安装GDAL。
# 由于没有安装sudo命令,所以在代码前面没有加上sudo获取管理员权限
apt-get update
apt-get install -y gdal-bin
# gdal-bin 是GDAL的二进制文件包,这里使用参数-y表示在安装过程中自动确认所有提示,避免手动输入确认信息。
接下来将北京水系的geojson文件拷贝到容器中,这里的docker cp
用于在宿主机和容器之间复制文件或目录。我这里直接使用 Windows 风格的路径,按照网上的教程等,建议使用WSL路径或者PowerShell风格路径,WSL路径就是将D:/
改为/mnt/d/
,PowerShell风格是在本地路径上加引号。以下代码将本地路径D:/Programs/DockerData/PostGIS/Data/
下的文件复制到容器的/opt/
文件夹下。
docker cp D:/Programs/DockerData/PostGIS/Data/BeijingWater.geojson postgis:/opt/BeijingWater.geojson
最后使用GDAL的**ogr2ogr
**函数将文件导入数据库,这里虽然写的是postgresql数据库,其实是postgis拓展;引号中的内容为PG数据库的连接信息,指定服务器地址、用户名、数据库名称、密码。
#进入容器
docker exec -it postgis bash
#使用ogr2ogr函数
ogr2ogr -f PostgreSQL PG:"host=localhost user=postgres dbname=mydatabase password=postgres" /opt/BeijingWater.geojson
# 查看是否已经导入,先切换到 postgres 用户,再查看数据库中的表
su - postgres
psql
# 查看所有的数据库 \l
#切换到特定数据库
\c mydatabase
# 查看所有的表
\dt
这里的110000便是加载到数据库的文件,该文件在网站下载时的名称为110000.geojson
,我重命名为BeijingWater.geojson
,但是导入后名称仍为110000
。我这里在数据库中将表重命名:ALTER TABLE "110000" RENAME TO BeijingWater;
。
(2)QGIS生成样式文件
打开QGIS,导入GeoJson文件,随意设置一个自己喜欢的样式,将样式导出为SLD文件格式。
(3)数据导入GeoServer
尽管在创建过程中,使用--link
在容器之间建立了网络连接,使得 GeoServer 容器可以通过主机名访问 PostGIS 容器,但不会自动配置 GeoServer 来使用 PostGIS 数据库。因此,还需要手动配置 GeoServer 使用 PostGIS 数据库。首先创建新的工作空间,设置工作空间的相关信息、启用相关的服务服务并保存。
新建存储仓库,矢量数据源选择PostGIS,然后编辑存储仓库的基本信息、连接参数,需要注意的是这里的host
填写容器名,而不是localhost
。
点击数据->样式,添加使用QGIS创建的样式,验证无误后保存。
发布新导入的图层,编辑图层基本信息、设置投影、设置边框、设置发布的样式等。这里由于编码原因等,没有正确显示中文的样式标注名称。
如果遇到样式文件(SLD)的中文标注没有正确显示,通常是由于字符编码或字体配置不正确导致的。我这里使用的UTF-8编码,应该是无误的;问题应该是出在字体,应该需要给Docker容器中的GeoServer添加中文字体。但是我没有修改,感觉使用Docker安装的geoserver存在问题,服务器状态中显示可用字体26个,但是查看可用字体时弹出:哎呀出错了,抱歉,服务器上发生了意想不到的事情
;我在Ubuntu系统中安装的geoserver有519种字体,因此可能JVM可用字体是与安装环境有关。等以后需要设置字体或有时间,我再来解决一下这个问题。
最后预览图层,无误即可。
2 项目搭建
原视频教程使用的vue.js、webpack、vue-cli等搭建的项目,我在这里直接使用的vite搭建的项目。
项目搭建第一步是创建vue项目,首先使用PowerShell导航到项目路径,然后创建项目,设置相关信息;安装相关依赖,最后启用项目查看。
# cd到路径
cd D:\WebLearn
# 搭建项目
npm create vue@latest
#执行如下命令
cd znlgis_dome
npm install #安装项目依赖
npm run format#格式检查,格式化代码,可以不运行
npm run dev#启动项目#安装项目依赖前可以先查看镜像
npm config get registry
#淘宝镜像
npm config set registry https://registry.npmmirror.com/
项目中主要使用其他框架包括 element-plus、vue3-openlayers。我们可以将element-plus、vue3-openlayers等进行全局安装,也可以在某个项目中单独安装,我没有全局安装。
# 全局安装,直接在powershell中运行代码
npm install -g element-plus
# 项目中安装
npm install element-plus
这里还需要安装vue3-openlayers:https://vue3openlayers.netlify.app/,该库提供了大量的组件,例如 ol-map
、ol-view
、ol-tile-layer
等。其中,ol-map
是所有其他组件的主要容器。
# 项目中安装 vue3-openlayers 及依赖
npm i ol ol-ext ol-contextmenu
npm i vue3-openlayers
# 安装完成后,可以使用npm list查看验证
在官网提供了一个在线预览:https://vue3openlayers.netlify.app/playground.html,我们也可以直接参考在线预览提供的代码。
此外,还需要安装axios用于 发送 HTTP 请求,安装 Base64 编码和解码。
npm install axiosnpm install base-64
#TS需要执行如下
npm i --save-dev @types/base-64
项目搭建的第二步是初始化一些页面,设置一些相关内容,作为一个简单的示例。视频教程使用的JS,我这里使用的TS,可能一些具体的细节与视频教程存在差异。首先在main.js或main.ts文件中引入所需要的组件,原视频教程添加如下代码:
import { Map, Layers, Sources } from 'vue3-openlayers'app.use(Map)
app.use(Layers)
app.use(Sources)
原教程提供的源码参考中使用了如下代码:
import OpenLayersMap from 'vue3-openlayers'app.use(OpenLayersMap)
在src/components
文件夹下新建组件OLMap.vue
,参考视频教程与在线预览提供的代码, loadTilesWhileAnimating
和 loadTilesWhileInteracting
是 OpenLayers 的 ol/View 组件的两个属性,用于控制地图瓦片的加载行为,可以显著在地图动画或用户交互时 提升交互体验。
<template><ol-map:loadTilesWhileAnimating="true":loadTilesWhileInteracting="true"style="width: 100%; height: 100%; position: fixed"><ol-viewref="view":center="center":rotation="rotation":zoom="zoom":projection="projection"/><ol-tile-layer><!--加载发布的服务 --><ol-source-tile-wmsurl="http://localhost:8765/geoserver/PostGIS/wms?service=WMS&version=1.1.0&request=GetMap&layers=PostGIS%3Abeijingwater&bbox=115.47742462158203%2C39.44697189331055%2C117.440673828125%2C40.9804801940918&width=768&height=599&srs=EPSG%3A4326&styles=&format=application/openlayers"layer="PostGIS:beijingwater"serverType="geoserver"/></ol-tile-layer></ol-map>
</template><script setup lang="ts">
import { ref } from 'vue'const center = ref([116.37, 40.26])
const projection = ref('EPSG:4326')
const zoom = ref(9)
const rotation = ref(0)</script>
最后修改根组件:
<script setup lang="ts">
import OLMap from './components/OLMap.vue'
</script><template><OLMap />
</template><style scoped></style>
3 GeoServer REST API
GeoServer REST API 简介
GeoServer官方用户手册提供了 REST API 的相关介绍:https://docs.geoserver.org/stable/en/user/rest/index.html#rest。官方文档指出 REST 是 使用的 Swagger 2.0 ,这里我先去了解了一下什么是Swagger
:https://swagger.org.cn/docs/specification/2-0/what-is-swagger/,简单来说 Swagger就是一个API文档生成工具,用于描述、生成、展示和测试 RESTful Web 服务的规范。
那么什么是RESTful Web 服务呢?这里我询问了一下常用的AI工具,得到了如下答复:
RESTful Web 服务是一种基于 REST(Representational State Transfer,表述性状态转移) 架构原则设计的 Web 服务。REST 是一种软件架构风格,通常用于构建分布式网络应用和服务;它通过 HTTP 协议提供简洁、可扩展和易于理解的 API。在 RESTful Web 服务中,每个资源都有一个唯一的 URI(统一资源标识符),并且通过标准的 HTTP 方法(如 GET、POST、PUT、DELETE
)来执行获取、创建、更新、删除操作。
而这里的API(Application Programming Interface,应用程序接口) 是一种允许不同程序之间进行通信的接口;它定义了程序之间如何交互,包括请求和响应的格式、数据类型、操作方法等。API 的类型多种多样,包括 Web API、库和框架 API、操作系统 API、远程过程调用(RPC)API、WebSocket API 和数据库 API 等。Web API 是一种通过 HTTP 协议在网络上提供服务的 API,其中 RESTful API 是最常见的一种。
为了更好的理解,可以用生活中的例子理解 RESTful Web 服务 和 API。在餐厅中,API就是店小二或者中间人,将前端点菜信息等传达到后端厨房,再将后端厨房生产的食物等送到前端餐厅的用户手中; RESTful Web 服务就是智能餐厅的点单系统,我们不用找某个具体的服务员,直接扫桌子上的二维码发送请求等, RESTful Web 服务就像是一个智能虚拟服务员,接收请求后,并通过标准的 HTTP 方法(比如 GET、POST
)与后端(厨房)进行通信,厨房也可以通过该系统将食物已做好等信息发送给顾客。
理解了什么是 RESTful Web服务和API之后,就很容易理解 GeoServer REST API了。简单来说:GeoServer REST API 是 GeoServer 提供的一个 RESTful 接口,允许客户端通过简单的 HTTP 调用检索有关 GeoServer 实例的信息并进行配置更改,支持通过 HTTP 的 GET
方法读取信息,以及通过 PUT、POST
和 DELETE
方法进行写入操作。
如下图所示(截图不全,详情见:https://docs.geoserver.org/stable/en/user/rest/index.html#rest),API有不少端点,常用的几个包括:工作区(Workspaces)用来管理 GeoServer 中的工作区;数据存储(Datastores)用来配置和管理数据存储;图层(Layers)用来创建、更新和删除图层;样式(Styles)用来上传和管理样式文件;服务设置(Services Settings)用来配置 WMS、WFS、WCS 和 WMTS 等服务;安全设置(Security)用来管理用户、用户组和角色。
我们还可以查看原始的REST配置API参考部分:https://docs.geoserver.org/stable/en/user/rest/api/index.html#rest-api,这里提供了API 详细信息、全局设置等内容。在API详细信息中,介绍了常见的状态代码以及他们的含义、文件格式的表示。
官方手册中也提供了一些应用案例、端口可以控制的图层格式等信息。
使用Apifox快速生成与GeoServer REST API交互的JavaScript代码
GeoServer REST API 不是特别标准,因此一些API管理工具可能无法引入,UP主znlgis使用了Apifox。Apifox是一款集API文档管理、接口调试、Mock服务、自动化测试等功能于一体的API管理平台,旨在为开发者和测试人员提供高效的一站式解决方案;融合了Postman、Swagger、Mock、JMeter等工具的优势,能够极大地提升团队协作和API开发的效率;该软件从官网免费下载即可,下载安装后,打开软件,导入数据。
以Layers
为例,复制链接。
粘贴链接到Apifox,点击继续。
弹出导入预览界面,点击确定导入。
接口导入成功:
接下来可以使用Apifox对具体的接口生成JavaScript代码片段,作为参考。
这里生成的代码片段仅作为参考,后续还需要根据生成的代码片段,修改、编写为一个完整的JavaScript文件。
解决跨域问题
解决跨域问题,可以修改GeoServer配置文件、使用Nginx、前端在vue.config.js
中配置代理等方法,原视频中在前面Docker安装了Nginx但其实并没有使用,而是前端代理解决了跨域问题。我使用的TS,因此修改vue.config.ts
文件,代码如下所示:
import { defineConfig } from 'vite' 定义Vite配置
import vue from '@vitejs/plugin-vue' 导入VUE插件以支持Vue.js开发
import base64 from 'base-64' 使用base64编码便于在http请求中使用Basic认证const AUTH = { user: 'admin', pass: 'geoserver' } 定义对象包括用户名和密码
const AUTH_BASE64 = base64.encode(`${AUTH.user}:${AUTH.pass}`)拼接用户名和编码,并使用Base64编码export default defineConfig({plugins: [vue()], 配置Vite插件,使用的VUE插件server: { 配置开发服务器相关设置proxy: {定义代理,用于将前端开发服务器的请求转发到GeoServer REST API'/geoserver': {首先定义代理的路径前缀,当请求路径/geoserver开头时触发代理target: 'http://127.0.0.1:8766/geoserver',代理的目标地址,我一开始用的8765端口,后来换了9866,127.0.0.1表示本地服务器headers: {代理请求添加自定义的 HTTP 头部'Content-Type': 'application/json',设置请求的 Content-Type 为 application/jsonAccept: 'application/json',设置请求的 Accept 为 application/json,接收 JSON 格式的响应Authorization: `Basic ${AUTH_BASE64}`, 设置请求的Authorization头部,使用定义的AUTH_BASE64进行Basic认证},changeOrigin: true, 允许跨域请求时改变请求的源rewrite: (path) => path.replace(/^\/geoserver/, ''),定义一个函数重写请求路径,将路径中的 /geoserver 前缀移除,以便正确转发到 GeoServer REST API},},},
})
上述配置信息中,配置了插件、代理规则等解决跨域问题、处理认证信息,将前端服务器的请求转到GeoServer REST API,代理的路径前缀是 /geoserver
,当请求路径以 /geoserver
开头时,会触发代理;代理的目标地址是 http://127.0.0.1:8766/geoserver
,这是 GeoServer REST API 地址;使用了 base-64
库对用户名和密码进行 Base64 编码。
封装REST API相关接口的调用
教程中主要封装了about、Layers、LayersGroups
相关接口,参考Apifox提供的代码片段定义了两个类:About和Layers。我个人感觉Apifox提供的代码貌似看不看都行,学习就是比着葫芦画瓢的过程,直接先把znlgis的代码搞懂,后续再遇到就比着葫芦画瓢呗。原教程中主要是调用了GET相关的接口,原教程提供的Layers.js
文件内容如下:
import axios from "axios"; 使用 axios 库来发送 HTTP 请求 定义Layers类
export default class Layers {异步方法,使用axios.get发送GET请求到GeoServer REST APIasync getLayers() { try-catch块捕捉错误,请求成功返回响应数据;否则打印错误信息try {const response = await axios.get('/geoserver/rest/layers');if (response.status === 200) {return response.data;} else {console.err(JSON.stringify(response));}} catch (error) {console.err(error);throw error;}};async getLayerGroups() {try {const response = await axios.get(`/geoserver/rest/layergroups`);if (response.status === 200) {return response.data;} else {console.err(JSON.stringify(response));}} catch (error) {console.err(error);throw error;}};我使用的TS,所以直接将图层组名称显式定义为了字符串layerGroupName: stringasync getLayerGroup(layerGroupName) {try {const response = await axios.get(`/geoserver/rest/layergroups/${layerGroupName}`);if (response.status === 200) {return response.data;} else {console.err(JSON.stringify(response));}} catch (error) {console.err(error);throw error;}};
}
上述代码定义了3个异步方法,用于从 GeoServer 的 REST API 获取图层和图层组的信息,分别用于获取图层信息、获取图层组信息、根据图层组名称获取特定图层组详细信息。在代码中,原教程使用的console.err
而不是 console.error
,但是我在网上搜console.err
并不是 JavaScript 的正确方法,可能是作者搞错了。
About.js
文件内容如下所示,定义了4个函数来获取GeoServer 的清单信息、状态信息、系统状态信息、版本号信息。
import axios from "axios";export default class About {async getManifest() {try {const response = await axios.get('/geoserver/rest/about/manifest');if (response.status === 200) {return response.data;} else {console.err(JSON.stringify(response));}} catch (error) {console.err(error);throw error;}}async getStatus() {try {const response = await axios.get('/geoserver/rest/about/status');if (response.status === 200) {return response.data;} else {console.err(JSON.stringify(response));}} catch (error) {console.err(error);throw error;}};async getSystemStatus() {try {const response = await axios.get('/geoserver/rest/about/system-status');if (response.status === 200) {return response.data;} else {console.err(JSON.stringify(response));}} catch (error) {console.err(error);throw error;}};async getVersion() {try {const response = await axios.get('/geoserver/rest/about/version');if (response.status === 200) {return response.data;} else {console.err(JSON.stringify(response));}} catch (error) {console.err(error);throw error;}};
}
此外,定义了一个名为 GeoServerRestApi
的类,它封装了对 GeoServer REST API 的访问,通过组合 About
和 Layers
类来提供对 GeoServer 的基本信息和图层管理功能的访问,GeoServerRestApi.js
代码如下:
import About from './About.js'
import Layers from "./Layers.js";export default class GeoServerRestApi {/*** Represents information about the GeoServer.* @type {any}*/about;/*** Represents the layers in the GeoServer.* @type {any}*/layers;在构造函数中分别创建About和Layers的实例constructor() {this.about = new About();this.layers = new Layers();}
}
4 OpenLayers简介
这一部分文本内容主要来源于UP主 znlgis 视频与其Github分享https://github.com/OpenGisToolbox,我们可以结合OpenLayers官网(https://openlayers.org/)及官网相关文档(https://openlayers.org/en/latest/apidoc/)来进行理解。
下面是UP主 znlgis 提供的openlayers基础知识简介内容:
地图(Map)
OpenLayers 的核心部件是 Map(ol.Map
)。它被呈现到对象 target 容器(例如,网页上的 div
元素)。所有地图的属性可以在构造时进行配置。ol/Map 类是 OpenLayers API 中的核心组件之一,它负责创建和管理整个地图实例。
视图(View)
ol.View
负责地图的中心点,放大,投影之类的设置。一个 ol.View
实例包含投影 projection
,该投影决定中心 center
的坐标系以及分辨率的单位,如果没有指定,默认的投影是球墨卡托(EPSG:3857
),以米为地图单位。 放大 zoom
选项是一种方便的方式来指定地图的分辨率,可用的缩放级别由 maxZoom(默认值为 28)、zoomFactor(默认值为 2)、maxResolution(默认由投影在 256×256 像素瓦片的有效程度来计算)决定。起始缩放级别 0,以每像素 maxResolution 的单位为分辨率,后续的缩放级别是通过 zoomFactor 区分之前的缩放级别的分辨率来计算的,直到缩放级别达到 maxZoom。
图层(Layer)
一个图层是资源中数据的可视化显示,OpenLayers 包含几种基本图层类型,在实际中多使用第一个与第三个。
ol.layer.Tile
用于显示瓦片资源,这些瓦片提供了预渲染,并且由特定分辨率的缩放级别组织的瓦片图片网格组成。ol.layer.Image
用于显示支持渲染服务的图片,这些图片可用于任意范围和分辨率。ol.layer.Vector
用于显示在客户端渲染的矢量数据。ol.layer.VectorTile
用于显示在客户端渲染的矢量瓦片数据。ol.layer.WebGLTile
用于提供预渲染、平铺的瓦片图像,按特定分辨率的缩放级别组织。
数据源(Source)
OpenLayers 使用 ol.source.Source
子类获取远程数据图层,包含免费的和商业的地图瓦片服务,如 OpenStreetMap、Bing、OGC 资源(WMS 与 WMTS)、矢量数据(GeoJSON 格式、 KML 格式…)等。当资源(source)与地图视图(view)的坐标系相同时,无需再次设置投影projection(默认与view坐标系一致),只有在资源与视图的投影不同的情况下,才需要在资源中明确指定 projection 属性来表示要素缓存的投影。
控件(Control)
控件是一个可见的小部件,其 DOM 元素位于屏幕上的固定位置。 它们可以涉及用户输入(按钮),或者仅提供信息; 位置是使用 CSS 确定的。 默认情况下,它们放置在 CSS 类名为 ol-overlay container-stop event
的容器中,但可以使用任何外部 DOM 元素。在Openlayers中多数Controls直接可以在地图上添加,比如 Navigation(导航栏)。第二类是需要放在Div元素中才能用。第三类需要放置在panel(面板)中的操作类似于网页HTML中button按钮,需要点击或绑定才能起作用。最后一类就是自定义类型的。
交互(Interaction)
Interaction是用来控制地图的,和控件一样的作用。不过它们的区别是控件触发都是一些可见的 HTML元素触发,如按钮、链接等,而交互功能不可见的,如鼠标双击、滚轮滑动,手机设备的手指缩放等。
几何(Geoms)
OpenLayers中的Geoms实际上指的是Geometry(几何对象),它是地图要素(Features)的核心部分,表示了空间数据的具体形状和位置。在OpenLayers中并没有直接名为Geoms的模块或类,而是通过ol/geom
模块提供了一系列几何类型,如点(Point)、线(LineString)、多边形(Polygon)、多点集合(MultiPoint)、多线串(MultiLineString)、多边形集合(MultiPolygon)等。几何对象不仅用于构造要素,还可以用于各种空间分析和交互操作,如计算面积、长度、进行交集、缓冲区分析等。同时,它们也是OpenLayers中渲染的基础数据结构。
覆盖物(Overlay)
Overlay这个组件在Openlayers 项目中是经常要用到的,使用的场景通常是作为弹窗,显示某点或者某区域的信息。它不是根据屏幕位置固定的,而是与地理坐标相关联,因此平移地图将移动 Overlay。常用的大致有三类,弹窗、标注、文本信息。每个覆盖物都会生成对应的HTML元素,所以我们也可以使用css来修改去样式。一个覆盖物最少需要一个元素,当数据量大时,元素节点过多会导致页面加载卡顿,不流畅。大数据量的绘制图还是使用图层最好。
样式(Style)
OpenLayers 提供了一种强大且灵活的方式来自定义地图上的矢量要素(如点、线、面)的样式,这些样式是通过 ol/style 模块中的 ol.style.Style 类和其他相关子类(如 ol.style.Icon、ol.style.Stroke、ol.style.Fill、ol.style.Text 等)来实现的。
格式(Formats)
OpenLayers中的Formats主要用于处理地理空间数据的读写和解析,它包含了多种格式支持,比如WKT(Well-Known Text)、GeoJSON、KML、GML等。这些格式类允许开发者在客户端将地图要素转换为特定格式的字符串或者从字符串反序列化为地图要素。
第三方插件
OpennLayers也提供了第三方插件来拓展OpenLayers,网址为:https://openlayers.org/3rd-party/
。在第三方插件中提供了vue3-openlayers,使用vue3-openlayers 还需要引入 ol、ol-ext、ol-contextmenu
。
ol-ext
是 OpenLayers 的扩展库,提供了额外的功能和控件,用于增强 OpenLayers 的功能,例如一些高级的地图操作工具、额外的图层类型支持等;ol-contextmenu
是一个为 OpenLayers 设计的右键菜单插件,允许开发者为地图添加自定义的右键菜单功能,提供了 open
、close
、beforeopen
等事件,开发者可以在这些事件中实现自定义逻辑。
5 图层树组织
Up主znlgis原教程提供的代码比较简单,仅仅包含了一个子组件DomeMap.vue,原教程提供的代码如下所示:
<template><Map.OlMap id="map" ref="mapRef" :controls="[]"><Map.OlViewref="view":center="center":projection="projection":zoom="zoom"/><Layers.OlLayerGroup v-for="group in dynamicLayerGroupList" :key="group.name" :title="group.name":visible="group.visible"><Layers.OlTileLayer v-for="layer in group.layers" :key="layer.name" :title="layer.name" :visible="layer.visible"><Sources.OlSourceTileWms :layers="layer.name" :url="layer.url"/></Layers.OlTileLayer></Layers.OlLayerGroup><Layers.OlTileLayer v-for="layer in dynamicLayerList" :key="layer.name" :title="layer.name":visible="layer.visible"><Sources.OlSourceTileWms :layers="layer.name" :url="layer.url"/></Layers.OlTileLayer><MapControls.OlLayerswitcherControl :collapsed="false"/><MapControls.OlZoomControl/><MapControls.OlContextMenuControl/><MapControls.OlScalelineControl/></Map.OlMap>
</template><script lang="ts" setup>
import {onMounted, ref} from "vue";
import type MapRef from "ol/Map";
import {Layers, Map, MapControls, Sources} from "vue3-openlayers";
import GeoServerRestApi from '../geoserver/GeoServerRestApi';const center = ref([40, 40]);
const projection = ref("EPSG:4326");
const zoom = ref(0);
const dynamicLayerList = ref([]);
const dynamicLayerGroupList = ref([]);
const mapRef = ref<MapRef | null>(null);onMounted(async () => {try {let geoServerRestApi = new GeoServerRestApi();let layers = await geoServerRestApi.layers.getLayers();let layerList = layers.layers.layer;layerList.forEach((layer: any) => {let layerName = layer.name;if (layerName === 'ne:countries') {dynamicLayerList.value.push({name: layerName,url: `/geoserver/wms`,visible: true,});} else {dynamicLayerList.value.push({name: layerName,url: `/geoserver/wms`,visible: false,});}});let groups = await geoServerRestApi.layers.getLayerGroups();for (let group of groups.layerGroups.layerGroup) {let groupName = group.name;let groupLayers = await geoServerRestApi.layers.getLayerGroup(groupName);let layerGroups = {name: groupName,layers: [],visible: false,};groupLayers.layerGroup.publishables.published.forEach((layer: any) => {if (layer["@type"] !== "layer") return;layerGroups.layers.push({name: layer.name,url: `/geoserver/wms`,visible: false,});});dynamicLayerGroupList.value.push(layerGroups);}} catch (error) {console.error("Failed to load layers:", error);}
});
</script><style scoped>
#map {width: 100%;height: 100%;position: absolute;top: 0;left: 0;
}
</style>
代码中使用了let
声明变量,但是这些变量都没有被重新复制,因此我们也可以将let
修改为const
(let
:声明一个变量后,允许变量的值被重新赋值;const
:声明一个常量,一旦赋值后,其值不能被重新赋值)。在VS Code中可以使用快捷键Ctrl+D
多光标选择,一次将let改为const。
需要注意的是,由于GeoServer国家样例数据是错误的,因此我将上述代码中默认加载的图层ne:countries
修改为了ne:populated_places
。最后修改App.vue
:
<script setup>
import DemoMap from './components/DemoMap.vue'
</script><template><DemoMap/>
</template>
启动项目,结果图如下所示,可以看到加载出了点坐标数据。我这里手动将PostGIS工作空间中的数据移动到了最前面,并打开了图层,可以看到北京水系也被加载到了页面中;页面右侧的图层列表就是图层树组织。