@cf-platform/map
v1.0.1
Published
地图库
Readme
@cf-platform/map
基于 MapLibre GL JS 和 Cesium 的地图二次开发框架。ZBZMap 对 MapLibre 和 Cesium 的地图加载、弹窗、控件等进行了抽象,使用相同的封装类和组件即可分别构建 Cesium 地图或 MapLibre 地图。
特性
- 🗺️ 双引擎支持 — 统一 API 同时支持 MapLibre GL JS(2D 高性能)和 CesiumJS(3D 可视化)
- 🏗️ 多图层类型 — 支持 OGC 标准地图服务(WMTS/WMS)、MVT 矢量切片、XYZ 瓦片、GeoJSON、模型图层、聚合图层等
- 🎨 丰富特效 — 内置雷达扫描、水波纹、扩散圆、飞线、动态立体墙等可视化特效
- ✏️ 标绘绘制 — 内置 40+ 种标绘类型,包括点线面、军事箭头、贝塞尔曲线、集结地等
- 🎯 地图工具 — 集成距离测量、面积测量、三角测量、通视分析等工具
- 📍 要素编辑 — 支持对绘制的要素进行拖动编辑、节点增删等修改操作
- 🔍 图层拾取 — 内置地图识别(Identify)功能,支持 hover 和 click 事件
- 🧭 控件支持 — 内置指北针、比例尺、鼠标位置等地图控件
- 📝 弹窗系统 — 支持普通浮窗和高级浮窗,可拖拽、可自定义样式
- 🚀 轨迹回放 — Maplibre 引擎支持多轨迹回放(扩展方法)
- 🌍 三维支持 — 支持地形加载、3D 模型(glb/gltf)、三维标注
环境依赖
- Node.js >= 18
- 支持 VUE / React / 原生 JS 等任意前端框架
安装
# npm
npm install cesium vite-plugin-cesium vite -D
npm install zbzmap
# yarn
yarn add cesium vite-plugin-cesium vite -D
yarn add zbzmap离线安装
下载离线包并放置到项目根目录:
npm install cesium vite-plugin-cesium vite -D
npm install ./zbzmap.tgz快速开始
1. 配置 Vite
在 vite.config.js 中添加:
import { defineConfig } from 'vite'
import cesium from 'vite-plugin-cesium';
export default defineConfig({
plugins: [cesium()],
})2. 引入样式
在程序主入口引入地图样式文件:
// main.js
import 'zbzmap/dist/style.css';3. 初始化地图
MapLibre 引擎(推荐用于 2D 系统展示,性能更流畅):
import { MapFactory } from 'zbzmap';
const mFactory = new MapFactory();
mFactory.createMap('maplibre', {
element: 'mapContainer',
loadedFn: (loadedMap) => {
// 添加底图
const layer = loadedMap.createLayer('XYZ', {
id: 'baseMap',
url: 'http://t3.tianditu.gov.cn/DataServer?T=vec_w&tk=你的key&x={x}&y={y}&l={z}'
});
loadedMap.layerCollection.add(layer);
}
});Cesium 引擎(推荐用于 3D 效果展示):
import { MapFactory } from 'zbzmap';
const mFactory = new MapFactory();
mFactory.createMap('cesium', {
element: 'mapContainer',
loadedFn: (loadedMap) => {
const layer = loadedMap.createLayer('XYZ', {
id: 'baseMap',
url: '你的底图URL'
});
loadedMap.layerCollection.add(layer);
}
});核心概念
MapFactory
地图工厂,用于创建地图实例。内部统一管理 Cesium 和 MapLibre 两种引擎的初始化。
const mFactory = new MapFactory();
const map = mFactory.createMap(mapType, mapOptions);地图参数(MapFactoryOptions)
| 参数 | 说明 | 类型 | 默认值 | 必填 |
| :--- | :--- | :--- | :--- | :--- |
| element | 地图容器元素 id 或 DOM 对象 | string \| HTMLElement | - | 是 |
| baseMap | 地图底图 URL | string[] \| string | - | 否 |
| center | 初始化视图中心 | LonLatArray \| LonLat | - | 否 |
| zoom | 缩放层级 | number | - | 否 |
| minZoom | 最小层级 | number | - | 否 |
| maxZoom | 最大层级 | number | - | 否 |
| allowRotate | 是否允许旋转 | boolean | true | 否 |
| loadedFn | 地图加载成功回调 | (map: IMap) => void | - | 否 |
| extendParams | 扩展参数(含右键菜单配置) | object | - | 否 |
| nativeParams | 原生地图引擎参数 | object | - | 否 |
IMap(地图实例)
地图创建后的返回对象,是操作地图的核心入口。主要成员:
| 成员 | 类型 | 说明 |
| :--- | :--- | :--- |
| layerCollection | ICollection<ILayer> | 图层集合 |
| effectCollection | ICollection<IEffect> | 特效集合 |
| popupCollection | ICollection<IPopup> | 弹窗集合 |
| controlCollection | ICollection<IControl> | 控件集合 |
| contextMenu | IContextMenuManage | 右键菜单管理 |
| identify | IMapIdentify | 地图识别 |
| clickEventManage | IClickEventManage | 事件管理器(防止事件冲突) |
| mapEvent | IMapEvent | 地图事件(ready/cameraChange/click 等) |
| mapInstance | any | 原生地图实例(Cesium Viewer 或 MapLibre Map) |
| extendMethods | - | 引擎扩展方法(如轨迹回放等) |
Collection(集合)
所有地图元素(图层、特效、弹窗、控件)都通过 Collection 统一管理:
| 方法 | 参数 | 返回值 | 说明 |
| :--- | :--- | :--- | :--- |
| add | item: T | void | 添加元素 |
| remove | item: T | void | 移除元素 |
| removeAll | - | void | 移除所有 |
| getValues | - | T[] | 获取所有元素 |
| getById | id: string | T \| undefined | 按 id 获取 |
| removeById | id: string | boolean | 按 id 移除 |
Collection 支持事件监听:
map.layerCollection.on('add', (layer) => { console.log('图层已添加', layer); });
map.layerCollection.on('remove', (layer) => { console.log('图层已移除', layer); });
map.layerCollection.on('clear', () => { console.log('集合已清空'); });图层
通过 map.createLayer() 创建图层,然后添加到 map.layerCollection 中显示。
const layer = map.createLayer(layerType, layerOptions);
map.layerCollection.add(layer);支持的图层类型
| 图层类型 | 说明 | 适用场景 |
| :--- | :--- | :--- |
| XYZ | XYZ 瓦片图层 | 天地图、OpenStreetMap 等标准瓦片服务 |
| MVT | 矢量切片图层 | Mapbox 格式矢量切片数据 |
| WMTS | OGC WMTS 服务 | 标准 WMTS 地图服务 |
| WMS | OGC WMS 服务 | 标准 WMS 地图服务 |
| Feature | 要素图层 | 业务数据承载,支持点线面及标绘要素 |
| GeoJSON | GeoJSON 图层 | GeoJSON 格式数据展示 |
| Model | 模型图层 | glb/gltf 3D 模型加载 |
| Cluster | 聚合图层 | 离散点数据聚合显示 |
ILayer 通用接口
所有图层继承自 ILayer:
| 属性/方法 | 说明 |
| :--- | :--- |
| id | 图层唯一标识 |
| show() | 显示图层 |
| hide() | 隐藏图层 |
| setOpacity(val) | 设置透明度 |
| setZIndex(val) | 设置层级 |
FeatureLayer 要素图层
用于业务数据的承载,是最常用的图层类型:
const layer = map.createLayer('Feature', { id: 'featureLayer' });
map.layerCollection.add(layer);
// 通过 WKT 添加要素
layer.addWktFeature('feat1', 'POINT(103 30)', {
pointSize: 10,
lineColor: '#ff0000',
fillColor: 'rgba(255, 0, 0, 0.5)'
});
// 通过 GeoJSON 添加要素
layer.addGeojsonFeature('feat2', geojsonData, styleOptions);
// 添加图片点
layer.addImagePoint('img1', [103, 30], {
image: '/marker.png',
scale: 0.5
});模型图层
const mLayer = map.createLayer('Model', { id: 'modelLayer' });
mLayer.addModel({
id: 'car',
url: '/car/car.gltf',
position: [103, 30, 0],
scale: 1,
angleParam: { h: 0, p: 0, r: 0 }
});
map.layerCollection.add(mLayer);MVT 矢量切片图层
const mvtLayer = map.createLayer('MVT', {
id: 'mvt',
style: {
sources: {
mySource: {
type: 'vector',
tiles: ['http://your-server/tiles/{z}/{x}/{y}.mvt?token=xxx'],
minzoom: 0,
maxzoom: 20
}
},
layers: [
{
id: 'myLayer',
type: 'fill',
source: 'mySource',
'source-layer': 'layerName',
paint: { 'fill-color': 'rgba(245,245,245,1)' }
}
]
}
});
map.layerCollection.add(mvtLayer);标绘绘制
内置丰富的标绘绘制工具,支持 40+ 种标绘类型。
// 开始绘制
map.startDraw('POLYLINE', (result) => {
console.log('绘制完成', result);
// result.feature 为绘制生成的要素
});
// 结束绘制
map.stopDraw();绘制类型一览
基础图形:
| 类型常量 | 说明 |
| :--- | :--- |
| POINT | 点 |
| POLYLINE / PLOTTING_POLYLINE | 线 |
| POLYLINE_FREE_HEADER | 手绘线 |
| POLYLINE_DASHED | 虚线 |
| POLYLINE_BEZIER | 贝塞尔曲线 |
| POLYGON / PLOTTING_POLYGON | 面 |
| POLYGON_FREE_HEADER | 手绘面 |
| POLYGON_BEZIER | 贝塞尔面 |
| CIRCLE_FREE_HEADER | 圆 |
| ELLIPSE_FREE_HEADER | 椭圆 |
| EXTENT_FREE_HEADER | 矩形 |
| ASSEMBLY_FREE_HEADER | 集结地 |
栅栏线:
| 类型常量 | 说明 |
| :--- | :--- |
| BOOM_POLYLINE | 左栅栏线 |
| BOOM_POLYLINE_RIGHT | 右栅栏线 |
| BOOM_POLYLINE_BEZIER | 左栅栏曲线 |
| BOOM_POLYLINE_BEZIER_RIGHT | 右栅栏曲线 |
箭头类:
| 类型常量 | 说明 |
| :--- | :--- |
| ARROW_STRAIGHT | 直箭头 |
| ARROW_STRAIGHT_LINE | 方向指示线 |
| ARROW_STRAIGHT_LINE_FREE_HEADER | 手绘方向指示线 |
| ARROW_STRAIGHT_DASHED_LINE | 方向指示虚线 |
| ARROW_STRAIGHT_LINE_ARC_BOTTOM | 弧底箭头线 |
| ARROW_SIMPLE | 单箭头 |
| ARROW_TAILED | 燕尾箭头 |
| ARROW_TAILED_TWO | 急行军 |
| ARROW_TAILED_THREE | 强行军 |
| ARROW_TAILED_TWO_HEADER | 攻击前进 |
| ARROW_TAILED_THREE_HEADER | 强突破 |
| ARROW_BIG_TAILED | 广角燕尾 |
| DOUBLE_ARROW | 钳击箭头 |
| DOUBLE_ARROW_BIG_TAILED | 无尾钳击箭头 |
注:大部分箭头类型都有对应的
_FREE_HEADER手绘变体。
要素编辑
支持对已绘制的要素进行拖动编辑修改。
// 编辑目标要素
map.startModify(feature, (result) => {
console.log('编辑完成', result);
// result.featurePoint - 特征点
// result.wkt - 编辑后的 WKT 几何
// result.feature - 原始要素
});
// 停止编辑
map.stopModify();注意:要素的
_geomProperties.featurePoints决定了编辑时的可拖动控制点数量。对于箭头类标绘(如方向指示线),控制点数量为 2。
特效
内置多种可视化特效,通过 map.createEffect() 创建:
const effect = map.createEffect('RadarScan', { id: 'radar' });
map.effectCollection.add(effect);
// 在指定位置添加特效实例
effect.add({
id: 'scan1',
position: [106, 31],
radius: 200000,
color: 'rgb(81, 217, 254)',
speed: 5
});支持的特效类型
| 特效类型 | 说明 |
| :--- | :--- |
| WaterWave | 水波纹 |
| DiffuseCircle | 扩散圆 |
| FlyLine | 飞线 |
| RadarScan | 雷达扫描 |
| DynamicWall | 动态立体墙 |
控件
const control = map.createControl('navigation', { id: 'nav' });
map.controlCollection.add(control);| 控件类型 | 说明 |
| :--- | :--- |
| mouse | 鼠标位置控件 |
| scale | 比例尺控件 |
| navigation | 指北针控件 |
弹窗
const popup = map.createPopup('normal', {
id: 'popup1',
position: [103, 30],
content: '<div>弹窗内容</div>',
renderInView: true // Cesium 引擎中仅在可视范围内渲染
});
map.popupCollection.add(popup);
// 更新弹窗位置
popup.setPosition([104, 30]);
// 移除弹窗
map.popupCollection.remove(popup);| 弹窗类型 | 说明 |
| :--- | :--- |
| normal | 普通浮窗 |
| advance | 高级浮窗(支持更多自定义配置) |
地图工具
内置分析测量工具:
// 面积测量
const tool = map.getTool('measureAreaTool');
tool.start();
tool.stop();| 工具名称 | 说明 |
| :--- | :--- |
| measureAreaTool | 面积测量 |
| measureLengthTool | 距离测量 |
| measureHeightTool | 三角测量 |
| sightLightTool | 通视分析 |
帮助类
通过 map.getUtil() 获取:
const zoomUtil = map.getUtil('zoom');
zoomUtil.zoomToPoint([103, 30]);
const geomEngine = map.getUtil('geometryEngine');
const point = geomEngine.createGeoJson('Point', [103, 31]);| 帮助类名称 | 类型 | 说明 |
| :--- | :--- | :--- |
| zoom | IZoomUtil | 地图缩放控制 |
| geometryEngine | IGeometryEngine | 空间分析 & 几何创建 |
| coordTrans | ICoordTrans | 坐标转换 |
| format | IFormat | 数据格式转换 |
地图事件
// 注册事件
map.mapEvent.on('ready', () => {
console.log('地图加载完成');
});
map.mapEvent.on('cameraChange', ({ zoom, center }) => {
console.log('视图变化', zoom, center);
});
// 解绑事件
map.mapEvent.off('ready', handler);
// 清除所有
map.mapEvent.clear('ready');| 事件名称 | 说明 | 回调参数 |
| :--- | :--- | :--- |
| ready | 地图加载完成 | - |
| cameraChange | 视图变化 | { zoom: number, center: LonLatArray } |
| click | 地图点击 | 原生事件对象 |
| dbclick | 地图双击 | 原生事件对象 |
| mousemove | 鼠标移动 | 原生事件对象 |
| onTerrainChange | 地形切换 | boolean(true=启用,false=关闭) |
右键菜单
// 普通菜单(点击空白区域时显示)
map.contextMenu.addMenuItem('normal', {
name: '菜单项',
clickFn: (e) => { console.log('点击了空白区域'); }
});
// 要素菜单(点击到要素时显示)
map.contextMenu.addMenuItem('feature', {
name: '要素操作',
clickFn: (e) => { console.log('点击了要素', e); }
});
// 自定义菜单(针对特定要素)
map.contextMenu.addMenuItem('custom', {
menuList: [
{ name: '自定义操作', clickFn: () => { console.log('操作'); } }
],
customFilterFn: (feature) => feature.id === 'targetId'
});地图识别(Identify)
map.identify?.localIdentify.startIdentify();
map.identify?.localIdentify.on('click', (result) => {
const { features, position } = result;
console.log('识别到要素', features.length, '个');
// 创建弹窗显示识别结果
const popup = map.createPopup('normal', {
id: 'identifyPopup',
position,
content: `识别到 ${features.length} 个要素`,
renderInView: true
});
map.popupCollection.add(popup);
// 停止识别
map.identify?.localIdentify.stopIdentify();
});
map.identify?.localIdentify.on('hover', (result) => {
console.log('移动到要素', result.features);
});地图常用操作
// 底图
map.setBaseMap('http://your-tile-url/{x}/{y}/{z}');
map.setBaseMap([]); // 清除所有底图
// 地形
map.setTerrain('http://terrain-url');
map.setTerrain(null); // 取消地形
// 区域掩膜
map.setRegionMask([[ [116.4, 39.9], [116.4, 39.9], [116.4, 39.9], [116.4, 39.9], [116.4, 39.9] ]]);
map.setRegionMask(null); // 取消
// 缩放
map.setZoom(10);
const zoom = map.getZoom();
// 中心点
const center = map.getCenter();
map.setMinZoom(3);
map.setMaxZoom(18);
// 旋转
map.setAllowRotate(false);
map.startRotate([103, 30], 1); // 中心点, 速度
map.stopRotate();
// 俯仰角
map.setAngle({ h: 0, p: -45, r: 0 }); // 方向角, 俯仰角, 翻滚角
// 获取分辨率
const resolution = map.getCurrentResolution();
// 手动刷新
map.updateRender();添加标记(仅 Maplibre)
const el = document.createElement('div');
el.innerHTML = '标记内容';
const marker = map.addMarker({
element: el,
position: [103, 30],
anchor: 'center',
offset: [0, 0]
});
marker.setPosition([104, 30]);
marker.remove();渲染回调
// 注册每帧渲染回调
const rc = map.registerAnimateProcess(() => {
console.log('每帧渲染');
});
// 移除
rc.remove();场景选点
map.startSelectPoint((pt) => {
console.log('经度', pt.lon);
console.log('纬度', pt.lat);
}, {
tipMessage: '请在地图上选点',
isContinuous: false // 是否连续选点
});
map.stopSelect();轨迹回放(Maplibre 扩展)
const feature = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[103, 31], [103.1, 31.2]]
},
properties: { id: 1 }
};
const track = map.extendMethods.addTrajectory(feature, {
icon: '/car.png',
speed: 20, // 米/秒
iconWidth: 20,
iconHeight: 40,
lineColor: '#28F',
lineWidth: 8,
isShowLineArrow: true,
isAgain: true // 是否重复播放
});
// 缩放至轨迹范围
map.getUtil('zoom').zoomToGeojson(feature);
// 播放控制
track.pause(false); // 暂停
track.pause(true); // 继续
track.stop(); // 停止
track.destroy(); // 销毁
// 事件监听
track.on('identify', (e) => { console.log('运动点识别', e); });
track.on('animate', (e) => { console.log('轨迹运动', e); });
track.on('pause', () => { console.log('轨迹暂停'); });地图引擎差异
| 特性 | MapLibre | Cesium | | :--- | :--- | :--- | | 维度 | 2D | 3D | | 性能 | 流畅 | 取决于场景复杂度 | | 适用场景 | 系统展示、数据可视化 | 三维效果、地形展示 | | 模型支持 | 有限 | glb/gltf 完整支持 | | 地形 | 有限 | 完整支持 | | 轨迹回放 | ✅ | ❌ | | Markers | ✅ | ❌ |
更新日志
v0.1.6
- 完善 MapLibre 引擎编辑功能(支持节点拖动、删除、ESC 取消等)
- 优化编辑模式下的顶点标记样式(区分编辑顶点、中点、浮动点)
- 修复 Cesium 引擎中线宽设置不生效的问题
- 修复 MapLibre 中无法移除 MVT 图层的问题
v0.0.2
- 修复 Cesium 引擎中设置线宽无法生效的问题
- 修复 MapLibre 中无法移除 MVT 图层的问题
License
ISC
