第06章 - 图层管理与地图控制

图层面板是 GeoLibre 的工作台核心:它既是数据的目录,也是绘制顺序、可见性、透明度、分组、刷新策略和一系列图层动作的入口。地图控制则是围绕地图画布的那一圈工具——控件、测量、右键分析、标注、评论、GPS 与录制。

本章有一条贯穿始终的线索:GeoLibre 不让你直接操作地图对象。你在面板上做的每一次改动,都是先写进状态仓库(store)里的图层记录,再由 MapController.syncLayers 把它协调成 MapLibre 的 source 与 layer。理解了这条单向数据流,很多事情就有了解释:为什么切换渲染引擎图层还在、为什么有的图层没有某个按钮、为什么拖动滑块很顺滑但不会产生几十条撤销记录。

说明:本章基于 GeoLibre 3.4。菜单项与参数名保留英文原文。素材来自 docs/user-guide/layers.md、docs/user-guide/map-controls.md、packages/map/src/layer-control-host.ts、packages/map/src/layer-sync.ts、packages/map/src/map-controller.ts、packages/core/src/history.ts 与 packages/core/src/types.ts。


6.1 图层栈:顺序、可见性与透明度

左侧的 Layers 面板按”最上面绘制 → 最下面绘制”的顺序列出工程里的所有图层,最后一行固定是底图 Background。选中某个图层会同时驱动右边的 Style 面板和下方的属性表。

操作 位置 行为
可见性 图层行上的眼睛按钮 切换单个图层的显示
隐藏全部 面板顶部的 Hide all layers 一次隐藏所有图层
排序(拖拽) 图层名旁的抓手(grip) 拖到另一个图层上即改变层级;拖拽只在面板内部生效
排序(按钮) 卡片上的 Move up / Move down 上移/下移一位
透明度 图层行上的滑块 0–100%

排列规则只有一句:列表越靠上越后绘制。底图(Background)永远在最底层,不参与排序。

提示:从 Finder/资源管理器往桌面应用里拖文件属于数据导入,与面板内部的图层拖拽是两条不同的路径,不会因为拖错位置而移动图层。

6.1.1 图层卡片上的图标按钮

选中图层后,卡片上会展开一排图标按钮。它们覆盖了高频动作:

按钮 作用 备注
Move up / Move down 在图层栈中上下移动一位 ——
Zoom to layer 把地图缩放到图层范围 仅对范围已知的图层有效
Identify features 点击地图上的要素查看属性 栅格图层改为读像素值;多波段栅格还会生成光谱剖面
Open Style panel 选中该图层并打开样式控件 与调色板按钮等价
Layer actions 打开完整菜单(见 6.1.2) … 按钮
Metadata 检视来源与配置,编辑描述性元数据 可 Export as STAC Item
Remove layer 从工程中删除 不删源文件

Identify features 在可编辑矢量图层上还会给每条结果附两个动作:

  • Edit geometry:打开 GeoEditor 并选中该要素;
  • Edit attributes:以编辑模式打开属性表并定位到该行。

Metadata 面板除了展示来源与配置,还能编辑描述性元数据:摘要(abstract)、关键字、许可、联系人、血缘(lineage)、时间范围、链接。Export as STAC Item 会把这份元数据写成一条 STAC Item——这是把工程里的图层变成可发布目录条目的最短路径。

6.1.2 Layer actions 完整菜单

… 菜单装下了其余全部动作。按用途归类如下。

图层与结构

菜单项 作用
Rename 改显示名(不改源)
Open Style panel 打开样式面板
New group from layer 用该图层新建一个分组
Edit geometry 交给 GeoEditor 做顶点级编辑
Load features into editor… 把要素复制进 GeoEditor 的草图图层
Open attribute table 打开该图层的属性表

选择与分析

菜单项 作用
Quick analysis 无对话框地对整层跑 buffer、centroids、convex hull、bounding box
Select features 交互选择:click / rectangle / polygon / freehand / radius,另有 Clear Selection
Select by Expression… 用属性表达式构建选择;也可作为持久化图层过滤器
Select by Location… 用空间关系构建选择(需要第二个图层)
Bind to Time Slider… 用该图层的日期或数值字段驱动时间轴

选择模式的修饰键是固定的:Shift 追加、Alt 移除、Shift+Alt 取交集、Esc 取消。

输出与互通

菜单项 作用
Export 导出数据、栅格、点云或三维模型(见 6.2.3)
Styles 导入/导出符号化(见第 7 章)
Save to My Data 把整层配置(来源、样式、标注、过滤、连接、虚拟字段、属性表单)存入个人库
Copy style / Paste style 在图层之间搬运符号化

同步与回写

菜单项 作用
Refresh / Auto refresh 立即重载或按间隔重载(WFS、GeoJSON URL)
Reload from disk / Watch file for changes 桌面版本地文件图层:立即重读或监听磁盘变化(替换上面的两项)
Save edits to source file 桌面版:把属性与几何改动写回 GeoJSON 或 GeoPackage 文件
Save edits to ArcGIS service / PostGIS table / SQL Server table 服务或数据库图层的回写项
Materialize to editable layer DuckDB 图层:把查询结果复制成可编辑的 GeoJSON 图层
Edit query in SQL Workspace SQL 查询图层:在 SQL 工作区重开该查询

不适用的条目会置灰:Select by Location 需要第二个图层,Paste style 需要剪贴板里有样式。

6.1.3 图层分组

分组是图层栈里的文件夹,可以嵌套,因此项目能拥有真正的层级而不是一条平铺清单。

操作 入口 说明
新建空组 New group 建一个空文件夹
用当前图层建组 New group from layer 把该图层包进新组
用多选建组 New group from selected layers 包住整个多选
移入 Move to group 移动一个图层
批量移入 Move selected layers to group 保持相对顺序
新建并定位 Add data to group 打开 Add Data,新图层直接进该组
组织 重命名、折叠/展开、上下移动、组级透明度 组级透明度作用于组内全部图层
排序 Sort A to Z / Sort Z to A 按名称排序,数字按自然序(Parcel 2 在 Parcel 10 前),忽略大小写
删除 Ungroup (keep layers) / Delete group and layers 前者解散保留图层,后者一起删除

分组有两条重要的语义规则:

  1. 组可见性与图层可见性是与关系。隐藏一个组会隐藏它内部的图层;一个图层若因为所在组不可见而不可见,面板会标注 Hidden because its group is not visible,以便与你手动关掉的图层区分。
  2. 组内图层必须连续。在共享的扁平图层数组里,同组图层必须挨在一起;一次会把某个图层与它的兄弟分开的移动(例如把它挪到一个子组之上,而兄弟还在下面)不会被执行,图层回到原位。

组级透明度是乘法:组的 opacity 乘进每个子图层自己的透明度,子图层存储的值不变。组与嵌套关系随工程保存,导入 QGIS 工程时也会把其分组树一并带过来。

6.1.4 混合模式(Blend)

Style 面板的符号化控件上方有一个 Blend 菜单,决定该图层的颜色如何与下方地图合成。透明度是把图层”稀释”,混合模式是把它”拌进去”。

模式 作用 典型用途
Normal 普通透明,默认 其余所有情况
Multiply 变暗:两色相乘 专题色或影像叠在山体阴影上
Screen 变亮:Multiply 的反向 把暗色图层从暗底图里提出来
Lighten 取较亮的颜色 叠加明亮要素而不压暗底图
Add 相加并趋向白色 发光、热力、密度叠加

混合作用于图层的填充、描边、点、标记与栅格瓦片。标注被刻意排除,始终按普通方式绘制——否则地名会跟着山体阴影一起变暗。

警告:点符号与三维建筑会混合两次。多边形、线与栅格瓦片以”整层”参与合成,同一图层内两个重叠多边形只与下方地图合成一次;但 MapLibre 对点符号与三维拉伸没有图层级合成步骤,每个符号各自合成。两个点符号在屏幕上重叠处会被混合两次,在 Multiply 下明显更暗。遇到这种情况,减小重叠(更小半径、聚合、比例尺相关的最小缩放)或把点转成多边形。

混合模式随工程保存,也会跟着复制样式的操作走,但它是 GeoLibre 的渲染设置,在 MapLibre/Mapbox 样式规范里没有对应项,因此导出为样式文件、SLD 或 QML 时会丢失。

为什么只有这五种?MapLibre 把所有图层画进一个 WebGL 画布,没有逐层混合 API,GeoLibre 只能用 GPU 的固定功能混合阶段实现——该阶段只能表达这五种。Photoshop 式的 Overlay、Color Dodge、Soft Light 需要在着色器里读画布已有颜色,每帧都要额外整帧拷贝,代价不可接受;Darken 与 Subtract 也不提供,因为它们的 GPU 方程会同时作用于透明通道,图层未覆盖的地方反而会把地图擦掉。

混合只在 MapLibre 绘制时应用,因此以下几类没有 Blend 菜单:

  • 3D Tiles、高斯泼溅、LiDAR 点云、deck.gl 叠加层(自绘 WebGL);
  • 通过 Add Data → Raster Layer 加的 COG(默认渲染引擎不是 MapLibre 图层);
  • 通过 Add Data → Vector Layer 加的矢量图层(由面板自己的控件绘制,不存在应用混合的时机)。

其余都能混合:本地与远程 GeoJSON、普通栅格图层(XYZ、WMS、WMTS)、PMTiles、MBTiles、矢量瓦片。

6.1.5 悬停提示总开关

当至少一个图层配置了悬停提示(hover tooltip)时,Layers 面板(以及只读查看器)会出现一个 Hover tooltips 复选框。取消勾选会暂停所有图层的悬停提示,重新勾选则恢复各图层原来的字段选择。

这是一个纯查看开关:它不会修改工程、不会把工程标记为已修改,工程重新打开时会自动恢复为开启。

6.1.6 撤销与历史预算

撤销与重做在 Edit 菜单里,位于选择工具之上;快捷键不在菜单层暴露,具体键位见 Help → Keyboard Shortcuts(或按 ?)。撤销以快照实现:每次在图内编辑矢量图层,都会压入一份包含该图层完整 geojson 的快照。这套机制有两个写在 packages/core/src/history.ts 里的参数:

参数 默认值 作用
historyCoalesceMs 400 ms 把连续的、会产生历史记录的改动(例如拖动透明度或样式滑块)合并成一条撤销记录
maxHistoryFeatureCount 500,000 跨快照保留的要素总数软预算

预算的计量方式值得一说:它统计去重后的要素数——多个快照共享同一份未改动图层的 geojson 时只算一次。内联 data: URL 的图层(例如被烘焙成像素的 NetCDF 网格)按每 200 字节折算一个要素计入,否则每次重设符号化都会写出一份新的数兆字节字符串,而快照看起来是”免费”的。

超过预算时丢弃最老的快照,但永远保留最新的一个——保证再大的图层也至少能撤销一步。所以在大图层上,可用的撤销深度会比小图层浅。


6.2 图层动作:缩放、识别、导出、刷新

6.2.1 缩放至图层

Zoom to layer 用图层的范围框住地图。三种情况需要区分:

  • 范围已知:正常缩放;
  • 范围未知(例如部分服务图层没有 bounds):不移动相机;
  • 瓦片图层:可以从 TileJSON 的 bounds 或已加载瓦片的要素范围推断(layer-control-host.ts 里 getLayerMetadataBounds 专门处理这条路径)。

6.2.2 识别与选择

识别(Identify) 与选择(Select) 是两件事:识别只是”看”,选择会改变要素的选中状态,进而影响属性表、导出与后续分析。

维度 Identify features Select features
触发 点击地图 选择工具激活后点击/框选
结果 弹窗列出属性 要素被标记为选中
栅格 读像素值;多波段生成光谱剖面 不适用
可编辑图层 附 Edit geometry / Edit attributes 选中后可在属性表批量编辑
结束 关闭弹窗 Esc 取消

选择模式共五种:click、rectangle、polygon、freehand、radius,另有 Clear Selection。

Select by Expression… 与 Select by Location… 把选择变成可表达的条件:

  • Select by Expression 可以只做一次选择,也可以把表达式应用为持久化图层过滤器——不新建图层,直接隐藏不匹配的要素。这是”定义查询(definition query)”的行为。
  • Select by Location 需要第二个图层作为参照,因此单图层工程里该项置灰。

注意:持久化表达式过滤器会保留表达式本身,但不会保留构建器里的 @ 变量。@map_zoom、@map_scale、@feature_count、@project_name、@layer_name 在点击 Filter layer 时已被替换成当时的值。若希望过滤器继续随相机变化,请写 ["zoom"] 而不是 @map_zoom。

有活动过滤器的图层,其图层行上会出现一个漏斗图标——这条视觉线索很重要,它让”被过滤”与”数据缺失”不会被混淆。Layer actions → Clear filters 会一次清空所有过滤控件但保留控件本身。

6.2.3 导出

导出菜单的内容随图层类型变化:

图层类型 可导出格式 说明
矢量 GeoJSON、GeoParquet、GeoPackage、KML、KMZ、zipped Shapefile、CSV(仅属性) 全部在浏览器内完成
栅格 GeoTIFF (COG)、Extract subset… 子集按框裁剪
LiDAR LAS、LAZ、COPC ——
三维拉伸的多边形 glTF(.glb)、OBJ、STL 需先把 Visualization 设为 3D extrusion

三维模型导出有几个必须知道的约定:

  1. 每个要素变成一个闭合实体(地面、墙面、屋顶),高度、基高、颜色与地图上绘制的一致;
  2. glTF 每个要素一个命名对象,属性作为自定义属性,每种颜色一个材质;Blender 用 File → Import → glTF 2.0 打开;
  3. OBJ 每个要素一个对象,颜色存在顶点上;
  4. STL 输出单个无颜色网格,面向三维打印与 CAD;
  5. 坐标以图层中心为原点的米为单位;glTF 与 OBJ 用 Y 轴向上,STL 用 Z 轴向上;glTF 在根对象上记录中心的经纬度;
  6. 高度不高于拉伸基高、或没有面积的要素会被跳过,并在提示里说明跳过了多少个。

6.2.4 样式互通与复制粘贴

图层级的样式互通是 Layer actions → Styles 子菜单,包含四类格式的导入导出(GeoLibre URL style、Mapbox GL style、OGC SLD、QGIS QML)、从文件或文本导入、以及 Style Manager 预设。这部分内容与”样式体系”高度耦合,放在第07章 样式符号化与图例展开。

Copy style / Paste style 是图层之间的快捷搬运:复制的是 LayerStyle 记录,不复制数据。批量场景请用 Project → Export → Export Layer Styles…(按图层名写出全部样式)与 Project → Import → Import Layer Styles…(按名字匹配应用)。

6.2.5 刷新与实时图层

可刷新的图层有两类:WFS 与 GeoJSON URL。

打开图层的刷新配置后可以选间隔:关闭、15 秒、30 秒、1 分钟、5 分钟、15 分钟,或自定义值;也可以随时手动刷新。

每个可重载图层都会把一条 connection 记录随工程保存,因此刷新节奏能跨保存与重开存活。记录字段(packages/core/src/types.ts):

export interface LayerConnection {
  layerId: string;
  interval: number | null;              // 秒;null 表示仅手动同步
  lastSyncedAt: string | null;          // 最近一次成功的 ISO 时间
  lastError: string | null;             // 最近一次错误,成功后清空
  onFailure: "keep-last" | "clear";     // 失败时保留旧数据还是清空
}

Layers 面板会显示同步状态(最近成功时间与最近错误)。onFailure 是两个完全不同的策略:

  • keep-last:刷新失败时保留上一份好数据,地图不会突然变空;
  • clear:刷新失败即清空,适合”宁可空也不显示过期数据”的场景。

桌面版对本地文件图层用另一套动作:Reload from disk 立即重读,Watch file for changes 在磁盘文件变化时自动重载。它们替换了网络图层的 Refresh / Auto refresh。

6.2.6 DuckDB 图层与 SQL 查询图层

从 DuckDB 数据源添加的图层,或由 SQL 工作区产生的图层,支持与普通矢量图层一样的识别、选择与属性表。它们的特殊之处在”结果如何变成数据”:

动作 结果
Materialize to editable layer 把查询结果复制成可编辑的 GeoJSON 图层,此后可改几何与属性
Edit query in SQL Workspace 回到 SQL 工作区修改查询
刷新 重新执行查询,结果替换当前图层内容

SQL 查询图层在渲染上是一条外部 deck.gl 图层,判定条件被抽成一个共享函数(packages/core/src/types.ts):

export function isDuckDBQueryLayer(
  layer: Pick<GeoLibreLayer, "metadata" | "type"> | undefined,
): boolean {
  return (
    layer?.type === "duckdb-query" &&
    layer.metadata.sourceKind === "duckdb-query" &&
    layer.metadata.externalDeckLayer === true
  );
}

三个条件同时成立才算。这个函数被 @geolibre/map、@geolibre/plugins 与桌面应用共用,目的是防止三方对”这是不是一个 DuckDB 查询图层”的判断发生漂移——比如插件在做就地几何编辑时必须跳过这类图层。


6.3 底图、行星与区域底图

底图是 Layers 面板最下面那一行 Background。它有两个入口:

  1. 双击该行打开 Change background 对话框;
  2. 从 Plugins 菜单激活 Basemaps 插件。

底图的可见性与透明度同样可以在图层面板里调。

6.3.1 可选的底图族

类别 内容 备注
OpenFreeMap 样式 Liberty、Liberty 3D、Positron、Bright、Dark、Fiord 无需密钥
Protomaps 样式 构建提供时出现 取决于构建配置
Regional(可折叠) 区域底图分组 面板里以分组形式展开
Blank 纯色背景 颜色由引擎的 blank 背景设置决定
Custom style URL 自填样式地址 需要可访问且允许跨域
行星底图 见 6.3.2 会同时设定椭球体

底图切换是工程级设置:它随工程保存,也会在分屏的各个面板间共享(Mapbox 引擎下另有 preferences.map.mapboxStyleUrl,ArcGIS 引擎下有 preferences.map.arcgisBasemap,见第 8 章)。

6.3.2 其他天体

GeoLibre 能画地球之外的世界。Change background 对话框与 New project 对话框都把这些底图分组:

分组 天体 数据来源
The Moon 月球 OpenPlanetaryMap
Mars 火星 OpenPlanetaryMap
Other celestial bodies(可折叠) 水星、金星、伽利略卫星(Io、Europa、Ganymede、Callisto)、Titan、Pluto、Charon USGS Astrogeology

USGS Astrogeology 的底图在加载时实时重投影到 Web Mercator,这样 MapLibre 才能渲染。

快速切换用 Layers 面板标题栏的行星切换器(轨道图标)。选择某个天体不只是换底图——它会设定工程的 ellipsoid(椭球体),此后距离、面积与比例尺都按该天体的半径计算,而不是地球的。

提示:这一条比看起来重要。GeoLibre 内置的椭球体里,月球长半轴 1,737,400 m、火星(IAU 2000)3,396,190 m,相差约一倍,同一段像素距离在两者上代表的实际长度差别极大。换天体后如果测量结果”不对”,先检查椭球体是否跟着换了(见第 8 章 8.9.5)。

6.3.3 底图与图层的合成顺序

底图永远在最底层,且不参与图层排序。你可以:

  • 关掉底图看纯数据(Blank 或隐藏 Background);
  • 把底图透明度调低,让上面的栅格或矢量成为视觉主体;
  • 用 Blend 的 Multiply 把专题色叠在山体阴影底图上(见 6.1.4)。

6.4 地图控件:Controls 菜单

Controls 菜单切换两类地图上的辅助元素:MapLibre 内置控件,以及提供 Measure、Bookmark 等工具的组件面板。菜单项前的勾表示当前显示。

6.4.1 内置控件

控件 说明
Navigation 放大/缩小按钮
Compass 指北针;点击把方位角复位为正北
Fullscreen 地图铺满屏幕
Geolocate 定位到当前位置
Globe 在平面地图与三维球面之间切换投影
Terrain 开关三维地形;双击控件设置垂直夸张系数
Scale 比例尺,单位由 Scale bar units 偏好决定
Elevation 在状态栏报告指针处地面高程(默认关闭)
Attribution 显示数据归属
Logos 显示/隐藏 MapLibre 与提供方 logo

6.4.2 组件工具

这些是 MapLibre components 插件提供的交互面板:

工具 说明
Search 按地名搜索并飞到结果
Colorbar 为栅格值显示连续色带
Legend 显示描述图上图层的图例
HTML 在地图面板里显示自定义 HTML
Image 把 https:// 图片(logo、指北针、图例)放到任意角;每张图有可折叠的标题栏,一张地图最多 20 张
Measure 交互测量距离与面积,含方位角与地形感知的三维读数
Bookmark 保存命名视图并跳回;书签与文件夹随工程保存
Minimap 当前范围的鹰眼图
View State 读写精确的 center、zoom、bearing、pitch

提示:由插件承载的控件可以放在任意角落。支持的插件在 Plugins 菜单里设置角落(top left、top right、bottom left、bottom right)。

Bookmark 有一个版本迁移细节:旧版本存在浏览器里的书签,会在你打开的第一个”没有任何书签”的工程时被复制进工程并保存;浏览器里的旧副本保留但不再更新。

6.4.3 默认可见性与默认位置

默认值写在 packages/map/src/map-engine.ts,所有引擎从同一张表出发,这样 Controls 菜单的勾选状态与地图上的实际状态不会分叉:

export const DEFAULT_BUILT_IN_CONTROL_VISIBILITY: Record<BuiltInMapControl, boolean> = {
  navigation: false,
  fullscreen: true,
  compass: true,
  geolocate: false,
  globe: true,
  terrain: false,
  scale: true,
  attribution: true,
  logo: false,
  "maptoolkit-logo": false,
  "layer-control": true,
};

默认位置同样集中定义:导航、全屏、指北针、定位、球面、地形与图层控件在 top-right;比例尺与 logo 在 bottom-left;归属信息在 bottom-right。

需要注意的是这正是”看起来少了一个按钮”的常见原因:Navigation 与 Geolocate 默认是关闭的,需要在 Controls 菜单里手动打开。

6.4.4 控件与引擎的适配

内置控件集合由 BuiltInMapControl 联合类型描述:

export type BuiltInMapControl =
  | "navigation" | "fullscreen" | "compass" | "geolocate" | "globe"
  | "terrain" | "scale" | "attribution" | "logo" | "maptoolkit-logo"
  | "layer-control";

不同引擎挂载同一套 id,只跳过自己无法承载的项。例如 Mapbox GL JS 没有自己的球面控件,于是引擎挂了一个替身控件来复刻 MapLibre 的按钮标记;Mapbox 的归属控件无法隐藏,Maptoolkit logo 又是 MapLibre 专属。详见第08章 渲染引擎与三维可视化。

6.4.5 地图上的 Layer Control

地图右上角的 Layer Control 是 Layers 面板的镜像。它与左侧面板共享同一份状态:

  • 列出工程图层,包括当前隐藏或仍在加载的图层;
  • 按相同的图层分组嵌套成可折叠文件夹,每个文件夹有自己的复选框与透明度滑块;
  • 拖拽图层或使用右键 Move 动作会改变工程的图层顺序;
  • 两处的开关、淡化、折叠互相同步;
  • 分组自身的图层始终保持连续,破坏连续性的移动不会被应用。

分屏视图里不会挂载第二个 Layer Control——它只属于主图。

在实现上,这个控件是引擎中立的:它只需要共享的样式 API(getLayer、getStyle、paint/layout 读写、moveLayer、fitBounds、styledata 事件)加 IControl,而 Mapbox GL JS 同样实现这些。原先把它绑死在 MapLibre 上的是 GeoLibre 自己的粘合代码(store 适配器、结构变化重建、就地状态镜像、样式编辑器往返),这部分被抽到 layer-control-host.ts 的 LayerControlHost,两个二维引擎各自提供一份 LayerControlHostAdapter。Cesium 没有样式文档,因此没有 host。


6.5 测量、视域与右键快捷分析

6.5.1 Measure 面板

Controls → Measure 打开一个含三种模式的面板:

模式 产出
Distance 多段折线
Area 多边形
Circle 从中心点的半径

流程是固定的:选模式与 Unit → 点 Start → 在地图上依次点击 → 双击或右键结束 → Clear All 清除。

Exact segment 是键盘路线:输入长度与方位角,点 Add 就精确延伸一段,无需在地图上点。追查地契描述或导线测量时,这条比手点准得多。

除距离与面积,面板还给出:

读数 说明
Heading 测线方向,度数加 16 方位名(例如 310° NW)
Final heading 到达端的方位
Terrain (3D) 开启三维地形后按坡度计算的距离

Heading 是真实的大圆初始方位,不是屏幕上的角度。 在墨卡托地图上,华盛顿到伦敦”看起来”正东,真实初始方位约 50°。三点以上的路径,Heading 取首点到末点的整体方向,而不是逐段一行。

Final heading 只在足够长的线上出现:大圆沿途会改变方向,只有收敛达到 1° 的线路才会单独给这一行。Terrain (3D) 在没有高程数据时自行隐藏;Heading 行不会隐藏,因为方位是坐标上的纯几何量,不需要 DEM。

6.5.2 右键快捷菜单

在地图上右键会打开以该坐标为中心的菜单:

菜单项 作用
坐标本身 等宽字体显示在顶部,点击复制到剪贴板
What’s here? 打开该地点的 Wikipedia 知识卡
Copy as GeoJSON 把点击点复制成 GeoJSON Feature
Center map here / Zoom in here 把相机移到该点,可选再放大一级
Quick analysis 一键分析子菜单(见 6.5.3)
View in Google Maps / View in Google Earth 在外部地图打开同一位置

6.5.3 从点击点做快捷分析

Quick analysis 直接在右键坐标上跑工具,不需要先建点图层:

动作 参数
Buffer … here 三档距离,跟随 Scale bar units:公制 500 m / 1 km / 5 km,英制 0.25 mi / 1 mi / 5 mi
Drive time from here 5 / 10 / 15 分钟驾车等时圈
Walk time from here 同样的步行等时圈
Viewshed from here 2 km / 5 km / 15 km 的通视范围(见 6.5.4)
Open in Processing… 打开完整的 Processing 矢量对话框,暴露预设没有的参数

结果作为新图层加入,横幅会报告进度与失败,并给出该次运行在 Processing History 里的入口。

同一套 Quick analysis 也出现在 Layers 面板每个矢量图层的动作菜单里,此时作用于整层:Buffer all features by …、Centroids、Convex hull、Bounding box。

警告:等时圈由 Valhalla 路径服务计算,默认是公共 FOSSGIS 实例 valhalla1.openstreetmap.de,因此你点击的坐标会离开本机。GeoLibre 首次使用会请求同意;自托管部署可以指向自己的服务。

6.5.4 从点击点计算视域

Quick analysis → Viewshed from here 计算从点击点可见的地形,并以半透明叠加层铺在地图上。

项 值
无需准备 DEM 高程来自地图三维地形控件所用的同一套公共地形瓦片,按点周围的方形区域按需抓取
观察点高度 1.8 m(站立的人),在地面高程之上
半径 2 km / 5 km / 15 km 三档;底层工具接受 100 m 至 50 km
结果 名为 Viewshed (5 km) 之类的图像叠加图层,因此有透明度、排序、缩放至、删除,并随工程保存
3D 地形 不需要开启

注意:快捷视域不建模地球曲率与大气折射。几公里内无所谓,但到 50 km 上限时,仅曲率造成的落差就约 180 m——做无线电视距研究时这就不可忽略了。公共地形瓦片也只是一套全球概化高程模型,不是测量级 DEM。需要严格分析时,请用 Processing → Whitebox Toolbox 里的 Viewshed 工具;这个快捷动作是刻意的补充而非替代。


6.6 相机、录制与环境工具

Controls 菜单还有一组工具:移动相机、把实时数据铺在地图上、或把看到的内容录下来。

工具 作用 是否访问外部服务
Sun 模拟任意日期时刻的太阳位置与昼夜分界线 否
Weather 叠加近实时的 Clouds(NASA 卫星影像,逐日动画)与 Precipitation(RainViewer 雷达,约近两小时动画) 是(NASA、RainViewer)
Gridlines 坐标网格与边缘标注,含 UTM 东距/北距模式与 MGRS/USNG 模式(含挪威与斯瓦尔巴特例外、带字母的 100 km 方格,放大后出现 10 km 与 1 km 线) 否
Spinning Globe 缓慢旋转球面,可限定区域 否
Route Animation 让标记沿线图层运动:播放/暂停、速度、拖尾、相机跟随 否
Flight Simulator 用连续键盘控制飞越地形与三维图层 否
Atmospheric Effects 低缩放时渲染深空背景、星空、彗星与大气光晕 否
Directions 点击地图加途经点并获取路线 是(公共 OSRM 演示服务器)
Reverse Geocode 点击地图反查地址 是(已配置的地理编码提供商)
Record Map Tour… 录制关键帧动画视频,支持逐关键帧重拍、停留与转场时长、可保存的巡游设置 否
Record Video… 录制地图画布或框选区域,可把地图上的 HTML、图例、色带面板烧进视频 否

地图导航基础(这些键位在任何引擎下都可用):

  • 平移:拖动地图,或在地图获得焦点时用方向键;
  • 缩放:滚轮、捏合、导航控件,或 + / -;
  • 旋转:按住右键拖动、点指北针,或 Shift + ← / →;
  • 俯仰:按住 Ctrl/Cmd 拖动,或 Shift + ↑ / ↓;
  • 复位:N 正北朝上、U 俯视、R 同时复位俯仰与方位。

提示:N、U、R 三个键是排查”地图歪了”的最快手段。三维模式下俯仰角很容易被误触累积。


6.7 标注、Elements 面板与评论

6.7.1 标注工具

标注直接画在地图之上,共八种:

工具 形态
Text 文本
Arrow 箭头
Rectangle highlight 矩形高亮
Ellipse highlight 椭圆高亮
Freehand highlight 手绘高亮
Pin marker 图钉
Sticky note 便签
Placed image 放置图片

每种都有颜色;描边类(Arrow、Rectangle、Ellipse、Freehand)还认线宽。可以删除最后一条或清空全部。工具栏顶部的折叠箭头用于收起工具,给下方控件腾位置。

标注随工程保存。

6.7.2 Elements 面板

Elements 面板列出所有标注,便于查找与管理,不用在画布上一个个找。锚定方式有两种:

锚定 行为
At Point 绑定一个地理坐标,随之移动(多数元素默认)
Pinned to Extent 拉伸到一个范围框,随视图缩放(Placed image 特有)

理解这两种锚定,才能解释”为什么我缩放后图片变形了”——Pinned to Extent 本来就是按框铺开的设计。

6.7.3 评论

评论是锚定的评审便签,与标注分开,因为它是对话而不是地图装饰。

  1. 在右侧栏的 Comments 面板激活评论工具,或按 C;
  2. 点击地图落一个图钉并写内容;
  3. 再按一次 C 关闭工具;
  4. GeoLibre 会问一次你的名字并记住。

每个图钉打开一个可回复的线程,可以 resolve、reopen、delete。面板可按 Open、Resolved、All 过滤;过滤为 Open 时,已解决的图钉不会显示在地图上。

在实时协作会话里,新增、回复、解决、删除都会同步给其他参与者。评论存在 .geolibre.json 里,因此即使没有会话在运行,它也会随保存或分享的工程一起走。


6.8 GPS 追踪与现场采集

Controls → GPS Tracking… 跟踪地图上的实时位置、记录轨迹日志,并可以直接从数据流数字化新要素。

Position source 有两个选项:

来源 说明
This device 浏览器或操作系统的定位 API,默认项,不需要额外硬件
NMEA receiver (serial or Bluetooth) 外接 GPS/GNSS 接收机,用于测量级或高频定位

选外接接收机时,需要选波特率,然后用 Connect serial 或 Connect Bluetooth 连接;对话框会显示设备名、已解析语句数与定位(fix)数的运行计数。

注意:读取接收机依赖 Web Serial 与 Web Bluetooth API,只有 Chromium 系浏览器(Chrome、Edge)提供,Firefox 与 Safari 没有。多数蓝牙 GPS 接收机讲的是经典蓝牙而不是低功耗蓝牙——这类先在操作系统设置里配对,配对后会以串口形式出现在这里;Connect Bluetooth 只用于低功耗蓝牙接收机。

启动 GPS 后可以:跟随位置、记录轨迹日志并存成图层、把轨迹导出为 GPX 或 GeoJSON、在你站立处捕获点。

Controls → Field Collection… 是相关工具,用于按自定义表单采集点、线、面观测,详见第10章 属性表、数据编辑与字段采集。


6.9 MapController.syncLayers:状态同步的概念模型

这是本章唯一需要读代码的部分,但它解释了很多现象。

6.9.1 单向数据流

用户操作 → Zustand store(layers 数组)→ MapCanvas 订阅
        → MapController.syncLayers(layers) → MapLibre source / layer

禁止 UI 直接改 MapLibre,改 store 让同步层去应用。这条规则来自 CLAUDE.md 与 docs/architecture.md,是整套架构的地基。

好处很直接:图层记录只有 id、类型、source、样式、可见性这些字段,与任何渲染引擎无关。因此切换引擎时相机、图层、分组、可见性、透明度与大部分样式都还在;也因此新增一个数据格式很便宜——只要能变成一条图层记录,就自动获得图层面板、透明度、排序、工程保存、样式导出的全部能力。

6.9.2 syncLayers 做的七件事

从 packages/map/src/map-controller.ts 的实现看,一次同步包含:

顺序 动作 细节
1 守卫 样式未就绪或地图未创建时直接返回
2 删除消失的图层 对比 id 集合,对不再存在的图层调用 removeLayerFromMap,并带上”仍然存活的 source id”集合,避免误删共享 source
3 自顶向下放置 layers 数组是”自下而上”,所以从末尾(最上层)往前走,每个图层插到”它上方那个图层”的第一个样式图层之下
4 记录快照 更新 layerIds 与 syncedLayers
5 混合模式 混合模式在渲染循环里读,不是 paint 属性,因此模式变化需要主动触发重绘
6 底图状态 应用底图可见性与透明度
7 外围同步 发布图层显示名、刷新地图上的 Layer Control、同步其状态、重绑聚合缩放监听与待处理的原生过滤器监听

第 3 步的方向是刻意选的,注释里给了原因:如果自下而上放置,一个图层会被锚到”还没被移动过的邻居”上,只要某个图层的原生样式图层是带外出现的(例如 Add Vector Layer 的恢复:控件在数据加载完成后才把图层加到样式顶部,远晚于首次同步),整个图层栈会在那一趟里错位。后续同步会收敛,但 ?maponly 的纯地图嵌入没有任何面板去触发后续同步,于是错误顺序就成了查看者一直看到的样子(issue #1404)。

6.9.3 混合模式的特殊处理

syncLayerBlendModes(layers) 之后还有一段:

const blendSignature = blendModeSignature(layers);
if (blendSignature !== this.blendSignature) {
  this.blendSignature = blendSignature;
  map.triggerRepaint();
}

为什么要单独触发重绘?因为混合模式不是 paint 属性,只在渲染循环里读;一个只改了混合模式、没改任何 paint 的图层,如果没有这一帧请求,地图不会重画。而签名是每个控制器自己保存的:混合模式注册表是模块级的,分屏时若按”注册表变了没”判断,第一个同步的面板会赢下差异,导致另一个面板停留在旧模式,直到某个无关事件逼它重绘。

6.9.4 与 Layer Control 的同步

Layer Control 不持有可见性账本。控件”应不应该在地图上”由引擎的内置控件记录决定,由它调用 LayerControlHost.add / remove。控件内部维护的 layerStates(每个图层的 visible、opacity、name)需要被就地镜像——上游控件没有公开的 setter,所以 host 直接改写它并调用其内部的 buildLayerItems 重建行。

另一个细节是底图识别:host 若能拿到可 fetch 的样式 URL,就让控件自己去分辨哪些样式图层是底图;拿不到时(Blank、GeoLibre 哨兵值、mapbox:// 样式)改用引擎报告的底图图层 id 集合预置 basemapLayerIds。否则控件会退化成”我挂载时地图上有什么,什么就是底图”,把工程图层一并当成底图,Background 开关一点就把数据图层关掉了。

提示:理解这一节之后,”为什么我改 store 但地图没动”和”为什么地图上多了一个控件看不见的图层”这两类问题就有了统一的排查入口:先确认同步是否跑过,再检查该图层是否被标记为控件自有(plugin-owned)或外部原生图层。


6.10 常见问题排查

现象 最可能的原因 检查动作
图层在列表里但地图上没有 图层被隐藏、所在组被隐藏、透明度为 0 看图层行标注是否写着 Hidden because its group is not visible;查组透明度
图层有漏斗图标但”数据像缺了” 有活动的快速过滤器或持久化表达式过滤 Layer actions → Clear filters
某按钮置灰 该动作对当前图层类型不适用 例如 Select by Location 需要第二个图层,Paste style 需要剪贴板有样式
缩放至图层无反应 图层范围未知 服务图层可能没有 bounds;瓦片图层需 TileJSON 或已加载瓦片
悬停提示不出现 全局 Hover tooltips 被取消勾选,或该图层没配 hover 字段 勾回复选框;检查 Popup 设计里的 In hover tooltip
点符号重叠处明显更暗 Multiply 混合对点符号逐符号生效 减小重叠或改用多边形(见 6.1.4)
立体拉伸导出 OBJ 打开后上下颠倒 坐标系别(glTF/OBJ 为 Y 向上,STL 为 Z 向上) 按目标软件改用对应格式
Layer Control 与面板不同步 控件自有图层或外部原生图层未被镜像 见 6.9.4;必要时折叠再展开连接/面板
刷新后地图突然变空 连接的 onFailure 为 clear 改为 keep-last
大图层拖动卡顿 要素数过大,GeoJSON 直接渲染 转 PMTiles(见第 5 章 5.6.4)

6.11 本章小结

  1. 图层栈:列表越靠上越后绘制,底图固定在最底层;顺序、可见性、透明度都有面板与地图控件两个入口。
  2. 图层卡片提供 Move、Zoom to layer、Identify、Style、Layer actions、Metadata、Remove 七个高频动作;… 菜单覆盖其余全部。
  3. 分组可嵌套,组可见性与图层可见性相与、组透明度相乘,组内图层必须连续,破坏连续性的移动会被拒绝。
  4. 混合模式只有 Normal/Multiply/Screen/Lighten/Add 五种,因为只能用 GPU 固定功能混合阶段实现;标注不参与混合;点符号与三维建筑会重复混合。
  5. 撤销以快照实现:400 ms 内合并成一条记录,跨快照要素软预算 500,000,超预算丢最老的快照但保留最新一个。
  6. 刷新策略存在 LayerConnection 记录里(interval、lastSyncedAt、lastError、onFailure),随工程保存;本地文件图层改用 Reload/Watch。
  7. 底图支持 OpenFreeMap/Protomaps/Regional/Blank/自定义样式,以及月球、火星与其他天体;换天体会改工程椭球体,进而改变量算结果。
  8. Controls 菜单分内置控件与组件工具两类;导航与定位默认关闭,图层控件默认开启。
  9. 测量除距离面积外给出真实大圆初始方位;快捷分析可对点击点跑缓冲、等时圈、视域;快捷视域不建模曲率与折射。
  10. syncLayers 是单向数据流的落地处:删消失、自顶向下放置、触发重绘、同步底图与 Layer Control,共七步。

6.12 实践练习

  1. 图层栈与分组:加载三个矢量图层,建两个嵌套组,把其中一个组设为 50% 透明度,观察组内图层与组外图层在视觉上的差异;再尝试把一个图层拖到”会把它与兄弟分开”的位置,记录面板的反应。

  2. 混合模式对比:加载一份山体阴影(或深色底图)与一份专题多边形,分别用 Normal 叠 60% 透明度、Multiply 叠 100% 透明度,比较两种做法的视觉效果,并说明为什么混合模式比降透明度更适合”让地形透出来”。

  3. 撤销预算实验:对一个中等矢量图层连续拖动透明度滑块 10 秒,然后撤销,记录撤销了几步;再用一个要素数明显更大的图层重复,比较可用撤销步数,并解释 500,000 这个软预算的作用。

  4. 视域精度:用 Quick analysis → Viewshed from here 在 2 km 与 15 km 两个半径下各算一次,然后把同一观察点交给 Processing → Whitebox Toolbox → Viewshed 用一份真实 DEM 再算一次,比较三者的边界差异,并写出快捷视域忽略了哪些因素。

  5. 实时图层:把一个 GeoJSON URL 图层的自动刷新设为 15 秒,在浏览器里观察同步状态的更新时间;随后故意让 URL 失效,记录 onFailure 为 keep-last 与 clear 两种设置下地图的不同表现。

  6. 控件复位:把地图旋转 40°、俯仰 50°,分别用 N、U、R 三个键,记录每次视图的变化,并说明这三个键各自复位了什么。


延伸阅读

  • 仓库文档:docs/user-guide/layers.md、docs/user-guide/map-controls.md、docs/architecture.md
  • 源码:packages/map/src/map-controller.ts(syncLayers)、packages/map/src/layer-sync.ts、packages/map/src/layer-control-host.ts、packages/map/src/map-engine.ts、packages/core/src/history.ts、packages/core/src/types.ts
  • 项目主页:https://geolibre.app