筆記參考教程來源于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工作空間中的數據移動到了最前面,并打開了圖層,可以看到北京水系也被加載到了頁面中;頁面右側的圖層列表就是圖層樹組織。