npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@loongbao-web-gis-utils/map-event-bus-core

v1.0.7

Published

Map Event Bus 核心逻辑层 - 业务事件总线

Downloads

552

Readme

使用手册

整体架构设计

MapEventBus 采用 Adapter(适配器)模式 设计,支持多种 GIS 框架。

┌─────────────────────────────────────┐
│           业务模块 A / B / C         │  ← 订阅 map:click 等业务事件
├─────────────────────────────────────┤
│      接入适配器层(framework-specific)│  ← 注册原生事件 + 坐标转换
│   adapter-openlayer / adapter-xxx    │
├─────────────────────────────────────┤
│         核心层(framework-agnostic) │  ← EventBus 发布订阅
│             packages/core            │
└─────────────────────────────────────┘
  • 核心层:框架无关的发布订阅事件总线(EventBus),提供 on/once/off/emit 基础能力
  • 适配器层:绑定特定 GIS 框架的原生事件,转换坐标,通过 EventBus 分发业务事件
  • 业务层:订阅 map:click / map:dblclick / map:pointermove / map:moveend 等业务事件

已有适配器

| 适配器包名 | GIS 框架 | 版本 | |---|---|---| | @loongbao-web-gis-utils/map-event-bus-openlayer | OpenLayers | v10.9.0 |


快速开始

安装

pnpm add @loongbao-web-gis-utils/map-event-bus-openlayer

依赖 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 } from '@loongbao-web-gis-utils/map-event-bus-openlayer'

// 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) => {
  const { center, bbox, zoom } = payload as { center: number[]; bbox: number[]; zoom: number }
  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 '@loongbao-web-gis-utils/map-event-bus-openlayer'

const bus = new OpenLayersMapEventBus(map)

constructor(map: OlMap)

创建实例,自动完成:

  1. 禁用 DoubleClickZoom 交互(通过 constructor.name 定位)
  2. 注册 click / dblclick / pointermove / moveend 原生事件
  3. click 带 300ms 防抖,双击不重复触发单击

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

  1. 取消 map 上所有原生事件监听(click/dblclick/pointermove/moveend)
  2. 清除未执行的 click 防抖 timer
  3. 清空 EventBus 所有订阅
  4. 恢复 DoubleClickZoom 交互

在 Vue 3 中使用

<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue'
import { OpenLayersMapEventBus } from '@loongbao-web-gis-utils/map-event-bus-openlayer'

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) => {
    const { zoom } = payload as { zoom: number }
    /* 处理移动结束 */
  })
})

onUnmounted(() => {
  mapEventBus?.destroy()
})
</script>

编写新适配器

以适配 Leaflet 为例:

1. 命名规范

| 项目 | 规范 | |---|---| | 包名 | @loongbao-web-gis-utils/map-event-bus-leaflet | | 类名 | LeafletMapEventBus | | 目录 | packages/adapter-leaflet/ |

2. 实现步骤

  1. 依赖 @loongbao-web-gis-utils/map-event-bus-coreEventBusIMapEventBus
  2. 实现 IMapEventBus 接口
  3. 构造函数中绑定框架原生事件:clickdblclickpointermovemoveend
  4. getCoord(e) 提取坐标转换为 [lng, lat](EPSG:4326)
  5. getMoveendPayload(e) 提取 { bbox, center, zoom }(EPSG:4326)
  6. destroy() 中解绑事件并清理 EventBus(需幂等)
  7. 分支覆盖率 >= 80%

3. 内部约束

  • 业务事件名称:map:clickmap:dblclickmap:pointermovemap:moveend
  • 坐标格式统一 [longitude, latitude]
  • click 需实现 300ms 防抖,双击不触发单击
  • dblclick 需阻止默认缩放行为(各框架实现不同)

注意事项

  1. 坐标格式:所有 emit 的坐标均为 [longitude, latitude](EPSG:4326)
  2. 销毁时机:组件卸载时务必调用 destroy(),避免内存泄漏
  3. 幂等性destroy() 可重复调用,不会抛出异常
  4. click 防抖:快速双击不会触发 click 事件,仅触发 dblclick
  5. 双击缩放:适配器自动禁用地图默认双击缩放,destroy 后恢复