Appearance
MapLibre 适配器(@geoverse/editor-libre)
MapLibre GL JS 是纯渲染库、无内置编辑。@geoverse/editor-libre 采用自绘范式:把要素、顶点句柄、变换手柄、绘制草图分别渲染成 GeoJSON source + 图层,自接 mousedown/mousemove/mouseup 等鼠标手势,归一成 editor-core 的命令——与 OpenLayers 适配器 共用同一引擎、同一命令、同一手感。
它接收一个 maplibre Map(@geoverse/core-libre 的 GMap 继承自 maplibre Map,可直接传入)。
为什么自绘,而非接入 Terra Draw / mapbox-gl-draw?
那些库自带 feature store,会与本架构「EditEngine 为唯一真源」冲突(需双 store 同步)。自绘让引擎保持唯一真源、两轨手感一致。详见仓库 docs/adr/0005。
安装
shell
pnpm add @geoverse/editor-core @geoverse/editor-libre @geoverse/core-libre maplibre-gl上手
ts
import { GMap } from '@geoverse/core-libre';
import { EditSession } from '@geoverse/editor-core';
import { LibreEditorAdapter } from '@geoverse/editor-libre';
import 'maplibre-gl/dist/maplibre-gl.css';
const map = new GMap({
container: 'map',
base: 'carto-light',
center: [118.15, 24.56],
zoom: 14,
});
const session = new EditSession({ crs: 'EPSG:4326', features: seed }); // seed 用经纬度
const adapter = new LibreEditorAdapter(map, {
onSelect: (id, additive) => {
if (id) session.select([id], additive);
else if (!additive) session.clearSelection();
adapter.setSelection(session.getSelected());
},
});
session.attach(adapter);
adapter.setMode('select');工作 CRS = EPSG:4326(度)
MapLibre 的 GeoJSON source 即 lng/lat,故 libre 轨工作 CRS 固定为 EPSG:4326,seed 坐标用经纬度。偏移/缩放的“距离”单位为度(非米),高纬度有形变;米制度量换算列入后续。
工具模式(adapter.setMode(mode))
模式集合与 OL 适配器一致:select / move / transform / modify / add-vertex / delete-vertex / split / split-polygon / merge / draw-point / draw-line / draw-polygon,归一到同一批命令。
绘制与按线拆面的收尾手势与 OL 略有差异(自绘):
| 能力 | OL 轨 | MapLibre 轨(自绘) |
|---|---|---|
| 绘制线/面 | ol/Draw 双击结束 | 逐点单击、双击结束,带橡皮筋预览;收尾去重相邻点 |
| 面拆分 | Draw 折线 | 在选中面上逐点单击画切割线、双击结束 |
| 顶点编辑 | ol/Modify | 拖自绘顶点句柄 → MoveVertexCommand |
| 选中高亮 | feature 样式 | MapLibre feature-state + paint 表达式 |
| 变换手柄 | ol/Pointer | 自绘 handles source + 拖拽 |
双击结束时适配器会临时禁用
doubleClickZoom,避免与地图双击缩放冲突。
顶点句柄显示
与 OL 轨一致,句柄按模式 + 选择集分三档(详见核心概念 · 顶点句柄显示):modify / add-vertex / delete-vertex 为实心可编辑句柄,select / move / transform 为更小更淡的「幽灵」句柄(自绘 paint 切换 circle-radius/透明度),绘制/拆分/合并不显示。句柄坐标用 editor-core 共用的 collectVertexHandles。整体平移/变换拖拽期间隐藏;顶点拖拽(modify)时自绘句柄随之移动。
非模式操作
与 OL 轨相同:镜像、偏移、点/面合并、多点拆分、复制粘贴由应用层对选择集直接派发命令(命令也从 @geoverse/editor-libre 转出):
ts
import { MirrorCommand, OffsetCommand } from '@geoverse/editor-libre';
const sel = session.getSelected();
session.engine.dispatch(new MirrorCommand(sel, 'vertical'));
session.engine.dispatch(new OffsetCommand(sel[0], 0.0004)); // 度面/多面运算与 OL 轨一致(命令通用,仅 CRS 单位不同):MergePolygonsCommand(不相邻 → MultiPolygon)、SplitMultiPolygonCommand(多面 → 多个面)、DifferencePolygonsCommand(布尔 A−B)、PunchHoleCommand(结构挖洞,B 作为 A 内环、须在 A 内部)、FillHoleCommand(填洞,移除内环,挖洞的逆操作)。差集是布尔运算(B 跨界切缺口),挖洞是结构插入内环(保留 A 外边界)。
面开洞 / 消洞(「非分离切」,命令与 OL 轨通用,仅工作 CRS 为 4326、坐标与宽度以度计;缺省宽度按面 bbox 对角线 0.5% 自适应,可 { width } 覆写)。**open-hole(线驱动,自绘模式)**选中含洞面→逐点画切割线、双击结束,把「从外边界进入某洞、不贯穿到对侧」的切割线所连通的洞连到外边界成凹湾(面仍 1 块、少一内环);**消洞 CloseHoleCommand(id)(一键,无需交互)**用凸包自动求出面上所有凹湾并封回内环洞,是开洞的逆向能力、与面填洞对称——直接 dispatch 即可,不用画线也不用点选。外边界为凸、无凹湾时报 CLOSE_HOLE_NO_BAY(普通带洞面只想去洞请用 FillHoleCommand)。
线/多线运算:MergeLinesCommand(端点相接 → 单线)、CombineLinesCommand(不要求相接 → MultiLineString)、SplitMultiLineStringCommand(多线 → 多条线)。
吸附
拖动顶点或绘制时,落点会自动吸附到既有要素的顶点与边。自绘适配器复用 @geoverse/editor-core 的 SnapIndex(与 OL 版同一吸附内核,手感一致);顶点拖拽会排除被拖要素自身,避免吸回原位。命中吸附点时该处显示橙色高亮环,光标也按模式(拖顶点 grab、选择 pointer、绘制 crosshair 等)给出可操作提示。默认开启,可配置或运行时切换:
ts
const adapter = new LibreEditorAdapter(map, { snap: true, snapTolerance: 10 });
adapter.setSnap(false); // 运行时关闭下一步
在线示例:仓库
examples/editor-libre/(pnpm dev:examples→/editor-libre/)。
