Skip to content

统一引擎门面 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

要素句柄支持统一读写:setVisiblegetId(libre 自动 gid;ol 需经逃生舱 setId 后有值)、Marker.getPosition/setPositionCircle.getCenter/getRadius/setRadiusPolygon/Polyline.getPath/setPath(坐标恒 WGS-84),以及圆/面/线的统一样式 setStyle({ strokeColor, strokeWeight, fillColor });图层支持 addFeatures 批量添加、removeFeatureByIdrefresh;视图支持 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 解码器(geoverseanim/),解码为整帧序列后由 AnimationPlayer 按时长逐帧驱动——OL 侧画到离屏 canvas 作 Icon 图标,libre 侧经 addImage 注册动图 StyleImageInterface(切底图后自动重注册)。
  • 进阶geoverse/olgeoverse/libre 另导出 AnimationPlayer / decodeAnimatedImage / OlMarkerAnimator / LibreMarkerAnimator,可自定义驱动任意 canvas / 图标。
  • 框架@geoverse/vue@geoverse/react 提供 GvAnimatedMarker 组件(暴露 play/pause/stop)。