Appearance
统一引擎门面 geoverse
geoverse 是一个门面包:用同一套 API 在 OpenLayers(@geoverse/core-ol)与 MapLibre(@geoverse/core-libre)两个渲染引擎间切换。它不替代两个核心,而是在其上提供:
- 统一的
createMap({ engine })建图入口(同步,非异步); - 统一的
IGMap接口 + 实例工厂方法(createMarker/createVectorLayer…),把两核心的公共能力收敛成一套; getEngine()逃生舱,触达引擎独有能力。
只用单一引擎、且不需要运行时切换时,直接用对应核心包更轻:
@geoverse/core-ol或@geoverse/core-libre(见引擎选型)。门面适合「同一套代码两引擎可切」或「想要一套引擎无关 API」的场景。
安装
门面把两个核心声明为可选 peer——按你走的入口装对应依赖即可:
shell
# 只用 ol 子路径
pnpm add geoverse @geoverse/core-ol ol
# 只用 libre 子路径
pnpm add geoverse @geoverse/core-libre maplibre-gl
# 主入口运行时切换:两套都装
pnpm add geoverse @geoverse/core-ol @geoverse/core-libre ol maplibre-gl三个入口:主入口 vs 子路径
| 入口 | 引擎 | 打包代价 | 用途 |
|---|---|---|---|
geoverse | 运行时 engine 选择 | 同时含 ol + maplibre | 真·运行时切换 |
geoverse/ol | 锁定 ol | 仅 ol(maplibre 不进 bundle) | 单引擎 ol,无浪费 |
geoverse/libre | 锁定 libre | 仅 maplibre(ol 不进 bundle) | 单引擎 libre,无浪费 |
子路径让单引擎应用零浪费,主入口保留真正的运行时切换。三者 API 一致,只差「能到达哪个引擎」。
ts
// 单引擎(推荐给绝大多数应用):同步、无浪费
import { createMap } from 'geoverse/ol';
const map = createMap({
target: 'map',
base: 'gd-vec',
center: [118.18, 24.49],
zoom: 12,
});
// 运行时切换:主入口,两引擎都在 bundle
import { createMap } from 'geoverse';
const map = createMap({
engine: 'libre',
container: 'map',
base: 'osm',
center: [120, 30],
zoom: 10,
});统一 API(公共能力面)
所有坐标对外一律 WGS-84 [lng, lat]。
ts
import { createMap } from 'geoverse/ol';
import '@geoverse/core-ol/style.css'; // 或 import 'geoverse/ol.css'
const map = createMap({
target: 'map',
base: 'gd-vec',
center: [118.18, 24.49],
zoom: 12,
});
// 视图导航
map.setZoomAndCenter(14, [118.2, 24.5]);
map.getCenter(); // [lng, lat]
map.getBounds(); // [minLng, minLat, maxLng, maxLat]
map.panTo([118.5, 24.7], { zoom: 13, duration: 800 }); // 平滑移动
map.fitBounds([118.0, 24.3, 118.6, 24.8], { padding: 20 });
map.isInBounds([118.2, 24.5]); // 是否在当前视野内
map.getDistance([118.09, 24.48], [119.3, 26.08]); // 球面距离(米),跨引擎数值一致
// 地图级统一事件(返回解绑函数,坐标 WGS-84)
const offClick = map.onPointer('click', (e) => console.log(e.lngLat));
const offMove = map.onViewChange((e) =>
console.log(e.center, e.zoom, e.bounds),
);
// 就绪门控(ol 同步立即回调;libre 走 style ready)
map.whenReady(() => {
// 工厂方法产出统一要素/图层(绕开按引擎静态 import 引擎类)
const layer = map.createVectorLayer({ id: 'pts' });
const marker = map.createMarker({ position: [118.18, 24.49], color: '#f00' });
marker.onPointer('click', (e) => console.log(e.lngLat)); // WGS-84
layer.addFeature(marker);
map.addLayer(layer);
// 弹窗
const info = map.createInfoWindow({
content: '<b>你好</b>',
position: [118.18, 24.49],
});
info.open();
});
// 运行时切底图(两引擎同名 API)
map.switchBase('bd-vec');工厂方法:createVectorLayer / createMarker / createCircle / createPolygon / createPolyline / createInfoWindow。
要素句柄支持统一读写:setVisible、getId(libre 自动 gid;ol 需经逃生舱 setId 后有值)、Marker.getPosition/setPosition、Circle.getCenter/getRadius/setRadius、Polygon/Polyline.getPath/setPath(坐标恒 WGS-84),以及圆/面/线的统一样式 setStyle({ strokeColor, strokeWeight, fillColor });图层支持 addFeatures 批量添加、removeFeatureById、refresh;视图支持 setMinZoom / setMaxZoom。
刻意保留的引擎差异(不做貌合神离的统一,走 getEngine() 逃生舱):地图旋转(ol 视图带 constrainRotation 档位吸附,与 libre 连续 bearing 语义不等价)、图层级显隐(libre 核心无图层 setVisible)、PNG 导出(libre 需建图时 preserveDrawingBuffer)、鹰眼(libre 无原生等价物)、以及各自独有图层/交互(OL 热力/海量点/聚合/路况/测量/绘制,libre 矢量切片/3D)。
建图项 scaleLine / fullScreen 两引擎均生效(ol 用内建控件,libre 适配为 ScaleControl / FullscreenControl);overview(鹰眼)仅 ol。
逃生舱 getEngine()
公共面只覆盖两核心的交集。引擎独有能力(OL 的热力/海量点/聚合/路况/测量/绘制/编辑,libre 的矢量切片/3D 倾斜…)经 getEngine() 取原始核心 GMap 后调用:
ts
import type { GMap as OlGMap } from '@geoverse/core-ol';
const ol = map.getEngine() as OlGMap;
ol.showTraffic(true); // OL 独有
ol.exportPng();ts
import type { GMap as LibreGMap } from '@geoverse/core-libre';
const libre = map.getEngine() as LibreGMap;
// 矢量切片 / 3D 等 libre 独有能力与框架组件的关系
@geoverse/vue / @geoverse/react 通过 geoverse/ol 消费 OpenLayers 引擎(默认 ol)。它们仍直接使用 OL 的原生能力(投影、原生事件、内置图层等);门面的统一 createMap 面向引擎无关的业务代码与运行时切换场景。
能力矩阵速查
| 能力 | geoverse/ol(OpenLayers) | geoverse/libre(MapLibre) |
|---|---|---|
统一 createMap / IGMap | ✅ | ✅ |
| 工厂要素(Marker/Circle/…) | ✅ | ✅ |
switchBase / 视图导航 | ✅ | ✅ |
| 热力 / 海量点 / 聚合 / 路况 | 经 getEngine() | — |
| 测量 / 绘制 / 要素编辑 | 经 getEngine() | 经编辑器三包 |
动图标注 createAnimatedMarker(APNG) | ✅ | ✅ |
| 矢量切片 / 3D 倾斜旋转 | — | 经 getEngine() |
动图标注(AnimatedMarker)
在普通 Marker 之外,门面提供 createAnimatedMarker 放置动图标注(当前支持 APNG,结构上为后续 GIF/WebP 扩展留口)。定位/重投影/datum 完全复用各引擎的普通 Marker,故与静态标注一致地正确落点、切底图不漂移。
ts
import { createMap } from 'geoverse/ol'; // 或 'geoverse/libre'
const map = createMap({
target: 'map',
base: 'gd-vec',
center: [116.4, 39.9],
zoom: 12,
});
const layer = map.createVectorLayer({ id: 'markers' });
map.addLayer(layer);
const m = map.createAnimatedMarker({
position: [116.4, 39.9],
icon: '/plane.apng', // 动图地址(APNG)
scale: 1,
});
layer.addFeature(m);
// 播放控制
m.pause();
m.play();
m.stop(); // 回首帧
// 丢弃前务必 destroy(停播 + 释放帧位图 / 注销图像)
m.destroy();- 实现:内置零依赖 APNG 解码器(
geoverse包anim/),解码为整帧序列后由AnimationPlayer按时长逐帧驱动——OL 侧画到离屏 canvas 作Icon图标,libre 侧经addImage注册动图StyleImageInterface(切底图后自动重注册)。 - 进阶:
geoverse/ol、geoverse/libre另导出AnimationPlayer/decodeAnimatedImage/OlMarkerAnimator/LibreMarkerAnimator,可自定义驱动任意 canvas / 图标。 - 框架:
@geoverse/vue、@geoverse/react提供GvAnimatedMarker组件(暴露 play/pause/stop)。
