@openlayer-utils/map-event-bus
v1.0.7
Published
Map Event Bus OpenLayers 适配层
Readme
使用手册
整体架构设计
MapEventBus 采用 Adapter(适配器)模式 设计,支持多种 GIS 框架。
┌─────────────────────────────────────┐
│ 业务模块 A / B / C │ ← 订阅 map:click 等业务事件
├─────────────────────────────────────┤
│ 接入适配器层(framework-specific)│ ← 注册原生事件 + 坐标转换
├─────────────────────────────────────┤
│ 核心层(framework-agnostic) │ ← EventBus 发布订阅
└─────────────────────────────────────┘- 核心层:框架无关的发布订阅事件总线(
EventBus),提供on/once/off/emit基础能力 - 适配器层:绑定特定 GIS 框架的原生事件,转换坐标,通过 EventBus 分发业务事件
- 业务层:订阅
map:click/map:dblclick/map:pointermove/map:moveend等业务事件
已有适配器
| 适配器包名 | GIS 框架 | 版本 |
|---|---|---|
| @openlayer-utils/map-event-bus | OpenLayers | v10.9.0 |
快速开始
安装
pnpm add @openlayer-utils/map-event-bus依赖 ol(peerDependency),需确保项目中已安装 ol >= 10.9.0。
基本用法
当前工具已经内置了防抖设计
import OlMap from 'ol/Map.js'
import View from 'ol/View.js'
import TileLayer from 'ol/layer/Tile.js'
import XYZ from 'ol/source/XYZ.js'
import { fromLonLat } from 'ol/proj.js'
import { OpenLayersMapEventBus, MoveendPayload } from '@openlayer-utils/map-event-bus'
// 默认配置
const mapEventBus = new OpenLayersMapEventBus(map)
// 自定义配置
const mapEventBus = new OpenLayersMapEventBus(map, {
debounceMs: 500,
enableMoveDuringDrag: true,
})
// 1. 创建地图
const map = new OlMap({
target: 'map',
layers: [
new TileLayer({
source: new XYZ({
url: 'https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
}),
}),
],
view: new View({ center: fromLonLat([109.5, 19.1]), zoom: 9 }),
})
// 2. 创建 MapEventBus 实例(自动监听地图事件、禁用双击缩放)
const mapEventBus = new OpenLayersMapEventBus(map)
// 3. 获取 EventBus 并订阅业务事件
const bus = mapEventBus.getEventBus()
bus.on('map:click', ([lng, lat]) => {
console.log('点击位置:', lng, lat)
})
bus.on('map:dblclick', ([lng, lat]) => {
console.log('双击位置:', lng, lat)
})
bus.on('map:pointermove', ([lng, lat]) => {
console.log('鼠标位置:', lng, lat)
})
bus.on('map:moveend', (payload: MoveendPayload) => {
const { center, bbox, zoom } = payload
console.log('移动结束:', zoom, center, bbox)
})单次订阅
bus.once('map:click', ([lng, lat]) => {
console.log('仅首次点击:', lng, lat)
})取消订阅
const handler = ([lng, lat]: number[]) => { /* ... */ }
bus.on('map:click', handler)
bus.off('map:click', handler) // 取消特定回调
bus.off('map:click') // 取消所有 click 回调销毁
当不再需要时调用 destroy() 清理资源。会取消所有原生事件监听、清空 EventBus 订阅、恢复双击缩放交互。支持重复调用(幂等)。
mapEventBus.destroy()API 设计
类型定义
type Coordinate = [number, number] // [longitude, latitude]
type EventType = 'map:click' | 'map:dblclick' | 'map:pointermove' | 'map:moveend'
type EventHandler = (payload: Coordinate | MoveendPayload) => void
interface MoveendPayload {
bbox: [number, number, number, number] // [minLng, minLat, maxLng, maxLat]
center: [number, number] // [longitude, latitude]
zoom: number
}IEventBus 接口(核心层)
interface IEventBus {
on(type: string, handler: EventHandler): void
once(type: string, handler: EventHandler): void
off(type: string, handler?: EventHandler): void
emit(type: string, payload: Coordinate | MoveendPayload): void
}| 方法 | 说明 |
|---|---|
| on(type, handler) | 注册持久订阅 |
| once(type, handler) | 注册一次性订阅,首次触发后自动取消 |
| off(type, handler?) | 取消订阅;不传 handler 则取消该类型全部 |
| emit(type, payload) | 触发事件,所有回调收到 payload |
IMapEventBus 接口(适配器层)
interface IMapEventBus {
destroy(): void
getEventBus(): IEventBus
getCoord(e: unknown): number[]
getMoveendPayload(e: unknown): MoveendPayload
}| 方法 | 说明 |
|---|---|
| constructor(map) | 接收框架地图实例,注册原生事件 |
| getEventBus() | 返回内部 EventBus,供业务方订阅 |
| getCoord(e) | 从原生事件提取坐标,转换为 EPSG:4326 经纬度 |
| getMoveendPayload(e) | 从地图视图提取 moveend 数据(bbox/center/zoom) |
| destroy() | 取消所有监听,清空订阅,恢复交互(幂等) |
OpenLayersMapEventBus 类
import { OpenLayersMapEventBus } from '@openlayer-utils/map-event-bus'
const bus = new OpenLayersMapEventBus(map)constructor(map: OlMap, options?: OpenLayersMapEventBusOptions)
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| debounceMs | number | 300 | 全局防抖时长,被具体类型覆盖 |
| clickDebounceMs | number | — | click 防抖时长(覆盖 debounceMs) |
| dblclickDebounceMs | number | — | dblclick 防抖时长 |
| pointermoveDebounceMs | number | — | pointermove 防抖时长 |
| moveendDebounceMs | number | — | moveend 防抖时长 |
| enableMoveDuringDrag | boolean | false | 拖拽地图时是否仍触发 pointermove |
创建实例,自动完成:
- 禁用
DoubleClickZoom交互(通过constructor.name定位) - 注册 click / dblclick / pointermove / moveend 原生事件
- click / dblclick / pointermove / moveend 均带防抖
- 拖拽地图时默认跳过 pointermove,可通过
enableMoveDuringDrag: true开启
getCoord(e: MapBrowserEvent<UIEvent>): number[]
返回 [longitude, latitude](EPSG:4326)
getMoveendPayload(e: MapEvent): MoveendPayload
返回值:
{
bbox: [minLng, minLat, maxLng, maxLat], // 视野范围(EPSG:4326)
center: [longitude, latitude], // 地图中心
zoom: 5 // 缩放级别
}destroy(): void
- 取消 map 上所有原生事件监听(click/dblclick/pointermove/moveend)
- 清除未执行的 click 防抖 timer
- 清空 EventBus 所有订阅
- 恢复 DoubleClickZoom 交互
在 Vue 3 中使用
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue'
import { OpenLayersMapEventBus } from '@openlayer-utils/map-event-bus'
let mapEventBus: OpenLayersMapEventBus | null = null
onMounted(() => {
mapEventBus = new OpenLayersMapEventBus(map)
const bus = mapEventBus.getEventBus()
bus.on('map:click', ([lng, lat]) => { /* 处理点击 */ })
bus.on('map:moveend', (payload: MoveendPayload) => {
const { zoom } = payload
/* 处理移动结束 */
})
})
onUnmounted(() => {
mapEventBus?.destroy()
})
</script>注意事项
- 坐标格式:所有 emit 的坐标均为
[longitude, latitude](EPSG:4326) - 销毁时机:组件卸载时务必调用
destroy(),避免内存泄漏 - 幂等性:
destroy()可重复调用,不会抛出异常 - click 防抖:快速双击不会触发 click 事件,仅触发 dblclick
- 双击缩放:适配器自动禁用地图默认双击缩放,destroy 后恢复
