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

ux-cesium

v0.0.6

Published

基于 Cesium 的地图标绘与点位管理库,支持 Primitive 聚合、动态 Label、弹窗、Plot 标绘、多边形分割合并与键盘漫游。

Readme

ux-cesium

基于 Cesium 的地图标绘与点位管理库,支持 Primitive 聚合、动态 Label、弹窗、Plot 标绘、多边形分割合并与键盘漫游。

安装

pnpm add ux-cesium

Peer 依赖:需在页面中全局引入 Cesium(window.Cesium)并初始化 window.viewer

快速开始

import {
  Plot,
  plotConfig,
  AddMarker,
  DragPoint,
  map,
  mapConfig,
  filterMap,
  keyboardMapRoamingInit,
} from 'ux-cesium'

keyboardMapRoamingInit(window.viewer)

AddMarker.add({
  list: [{ lng: 114.11, lat: 22.60 }],
  name: '视频',
  icon: '/icons/camera.png',
})

filterMap(window.viewer, { invertColor: true, filterRGB: [60, 145, 172] })

导出 API

| 导出 | 说明 | |------|------| | Plot | 标绘主类:绘制、编辑、分割、合并、历史记录 | | plotConfig | 内置标绘类型配置列表 | | AddMarker | 点位 / 线 / 面 / 聚合 / 文本 / 弹窗 | | AddBuffer | 缓冲区域绘制 | | DragPoint | 拖动可拖拽点位,支持范围限制与自定义校验 | | map | 地图工具(初始化、飞行、量算等) | | mapConfig | 地图中心、底图、Provider 等配置 | | filterMap | 底图色彩滤镜 | | keyboardMapRoamingInit | 键盘控制相机漫游 |


AddMarker 点位

import { AddMarker } from 'ux-cesium'

// type: billboard | label | text | polygon | polyline | clusterPoint | modal
AddMarker.add({
  list: [{ lng: 114.11, lat: 22.60 }],
  type: 'billbord',
  name: '图层名',
  icon: '/icon.png',
  config: {},
})

AddMarker.selected(data, config)
AddMarker.get('图层名->id', isData)
AddMarker.del('图层名')
AddMarker.del('图层名->id')
AddMarker.show('图层名', true)

聚合点位(PrimitiveCluster)

AddMarker.add({
  type: 'clusterPoint',
  list: [{ lng: 114.11, lat: 22.60 }],
  name: '聚合点',
  icon: '/icon.png',
  clusterIcon: '/cluster.png',
})

跟随文本(type: text

始终显示在地图上,随相机移动同步更新位置。html 须为 Vue VNodedefineComponent,内部通过 createApp 挂载,不支持纯 HTML 字符串

import { defineComponent, h } from 'vue'
import { NInput } from 'naive-ui'
import { AddMarker } from 'ux-cesium'

AddMarker.add({
  type: 'text',
  name: 'text-layer',
  list: [
    { lng: 114.113, lat: 22.602, html: h('div', {}, '纯文本') },
    { lng: 114.114, lat: 22.604, html: h(NInput, { modelValue: '' }) },
    { lng: 114.115, lat: 22.605, html: h('div', { innerHTML: '<b>富文本</b>' }) },
    { lng: 114.116, lat: 22.606, html: defineComponent({ render: () => h(MyComponent, { foo: 1 }) }) },
  ],
  config: {
    margin: { left: 0, top: 0 },           // 相对点位屏幕坐标偏移
    transform: 'translate(-50%,-110%)',    // CSS transform
  },
})

也可直接调用 AddMarker.textFn({ list, name, config }),参数与上述一致。

悬浮弹窗(type: modal

加载 billboard 点位,鼠标悬停点位时展示弹窗,移出弹窗或移开点位后关闭。

import { h } from 'vue'
import { NInput } from 'naive-ui'
import { AddMarker } from 'ux-cesium'
import pointImg from '@/assets/images/plot/火点.png'

AddMarker.add({
  type: 'modal',
  name: 'quyu-marker',        // 点位图层名
  icon: pointImg,             // 默认图标,单项可设 item.icon
  list: [
    { lng: '114.063', lat: '22.532', html: h('div', { class: 'tip' }, '悬停显示') },
    { lng: '114.069', lat: '22.537', html: h(NInput, { modelValue: '' }) },
  ],
  config: {
    margin: { left: 0, top: 0 },
    transform: 'translate(-50%,-110%)',
  },
})

// 删除点位图层(含 hover 监听)
AddMarker.del('quyu-marker')

// 仅删除当前悬浮弹窗(图层名自动为 '{name}-modal')
AddMarker.del('quyu-marker-modal')

| 参数 | 说明 | |------|------| | name | 点位图层名;弹窗图层自动命名为 {name}-modal | | list[].lng / list[].lat | 经纬度,必填 | | list[].html | 弹窗内容,必填,须为 VNode / defineComponent | | list[].icon | 可选,覆盖默认点位图标 | | config.margin | 弹窗相对点位屏幕坐标偏移 { left, top } | | config.transform | CSS transform,默认 translate(-50%,-110%) |

modalFn(单独弹窗)

一般由 type: 'modal' 内部在悬停时自动调用,也可手动指定单个弹窗:

AddMarker.modalFn({
  name: 'my-modal',
  item: {
    lng: 114.113,
    lat: 22.602,
    html: h('div', {}, '弹窗内容'),
  },
  config: {
    margin: { left: 0, top: 0 },
    transform: 'translate(-50%,-110%)',
  },
})

鼠标移出弹窗时会自动 AddMarker.del(name) 关闭。

html 写法(text / modal 通用)

| 写法 | 是否有效 | |------|----------| | h('div', {}, '文字') | ✓ | | h(NInput, { modelValue: '' }) | ✓ | | h('div', { innerHTML: '<b>html片段</b>' }) | ✓ | | defineComponent({ render: () => h('span', {}, '...') }) | ✓ | | '<div>222</div>' 纯字符串 | ✗ |

hdefineComponent<script setup> 中通常已通过 unplugin-auto-import 自动导入;普通 .js 文件需手动从 vue 引入。


DragPoint 拖动点位

配合 AddMarker.add 使用:列表项需设置 drag: true 才允许拖动。

import { AddMarker, DragPoint } from 'ux-cesium'

// 1. 先添加可拖动点位
AddMarker.add({
  name: '火点',
  icon: '/images/plot/火点.png',
  list: [
    { lng: 114.063, lat: 22.532, drag: true },
    { lng: 114.069, lat: 22.537, drag: true },
  ],
})

// 2. 启用拖动(默认开启吸附)
const drag = new DragPoint({
  viewer: window.viewer,
  enableSnap: true,
  snapDistance: 20,
  snapTypes: ['vertex', 'edge', 'center'],

  // 多边形范围:点位序列围成区域,超出则回退到按下时的位置
  bounds: [
    [114.0, 22.0],
    [114.5, 22.0],
    [114.5, 22.8],
    [114.0, 22.8],
  ],
  // 或 bounds: [{ lng: 114, lat: 22 }, ...]
  // 也可传入标绘多边形的 pos 坐标:polygonRow.pos.map(([lng, lat]) => [lng, lat])

  // 自定义校验:返回 true 阻止移动并回退
  beforeMove({ lng, lat, height, cartesian, start }) {
    // start 为拖动起点 { lng, lat, height, cartesian }
    return false
  },

  callback({ lng, lat, height, blocked }) {
    // 每次 mousemove 触发;blocked 表示本次是否被 bounds/beforeMove 拦截
  },
})

// 运行时更新
drag.setBounds([[114, 22], [115, 22], [115, 23], [114, 23]])
drag.setBeforeMove(({ lat }) => lat > 23)
drag.setBounds(null)       // 取消范围限制
drag.setBeforeMove(null)   // 取消自定义校验

// 销毁(移除鼠标监听)
drag.updateAction()

| 参数 / 方法 | 说明 | |-------------|------| | bounds | 多边形顶点数组,至少 3 点,首尾自动闭合 | | beforeMove | 返回 true 阻止移动并回退到起点 | | enableSnap | 是否吸附其他图形顶点,默认 true | | callback | 拖动过程坐标回调,含 blocked 字段 | | setBounds(points) | 动态设置/清除多边形范围 | | setBeforeMove(fn) | 动态设置/清除校验函数 | | updateAction() | 销毁实例,释放事件与吸附资源 |


Plot 标绘

基础用法(参考 PlotPanel.vue

import { Plot, plotConfig } from 'ux-cesium'

const defaultConfig = {
  pointSize: 1,
  textColor: '#fff',
  textSize: 16,
  style: 'solid',
  color: '#BCA00D',
  borderColor: 'red',
  borderSize: 4,
  labelShow: true,
  alpha: 0.2,
}

const plotData = ref([])

// 点击工具栏开始绘制
function plotClick(item) {
  new Plot({ ...defaultConfig, ...item }, (e) => {
    plotData.value.unshift(e.getData())
  })
}

// 载入已有数据
function showData() {
  const parent = window.viewer.entities.getOrCreateEntity('父实体-可有可无')
  plotData.value.forEach(async (item) => {
    const plot = await Plot.toData(item, null)
    plot.addDraw.parent = parent
  })
}

// 点击地图进入编辑
function initEditClick() {
  const handler = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas)
  handler.setInputAction((evt) => {
    const pick = window.viewer.scene.pick(evt.position)
    if (pick?.id?.objId || pick?.id?.startsWith('plot')) {
      const row = plotData.value.find(
        (o) => o.config.objId === pick.id?.objId || pick.id === o.config.objId,
      )
      if (!row) return
      Plot.edit({ curData: row, moveMultiple: true }, () => {
        plotData.value = plotData.value.filter((o) => o.config.objId !== row.config.objId)
      })
    } else {
      Plot.edit({ hide: true })
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}

// 删除
Plot.clear(objId)

多边形编辑(参考 PolygonEdit.vue

支持绘制、分割、合并、覆盖删除、撤回重做、顶点吸附、多选编辑。

import { Plot } from 'ux-cesium'

const plotData = ref([])
const historyManager = ref(Plot.createHistoryManager(50))
let curSelPlot = []

// 绘制多边形
function drawPolygon() {
  new Plot(
    { type: 'polygon', double: true, color: 'red', alpha: 0.6, borderColor: 'red' },
    async (e) => {
      await Plot.executeWithHistory(
        historyManager.value,
        plotData,
        () => {
          plotData.value.unshift(e.getData())
          return Promise.resolve()
        },
        '绘制图形操作',
        'draw',
      )
    },
  )
}

// 分割:先选中目标多边形,再绘制 brokenLine 折线
async function splitPolygon(splitLineData) {
  await Plot.executeWithHistory(
    historyManager.value,
    plotData,
    () => {
      const result = Plot.performPolygonSplit(
        plotData, curSelPlot, splitLineData, defaultConfig, configs, showData,
      )
      return result.success
        ? Promise.resolve(result)
        : Promise.reject(new Error(result.message || '分割失败'))
    },
    '分割多边形操作',
    'split',
  )
}

// 合并:Ctrl 多选至少 2 个多边形
async function mergePolygon() {
  await Plot.executeWithHistory(
    historyManager.value,
    plotData,
    () => {
      const result = Plot.performPolygonUnion(plotData, curSelPlot, defaultConfig, configs, showData)
      return result.success ? Promise.resolve(result) : Promise.reject(new Error(result.message))
    },
    '多边形合并操作',
    'merge',
  )
}

// 覆盖删除:选中 1 个多边形作为边界
async function coverageDelete() {
  await Plot.executeWithHistory(
    historyManager.value,
    plotData,
    () => {
      const result = Plot.performCoverageDelete(plotData, curSelPlot, defaultConfig, configs, showData)
      return result.success ? Promise.resolve(result) : Promise.reject(new Error(result.message))
    },
    '覆盖删除操作',
    'coverage_delete',
  )
}

// 进入编辑(点击图层或地图 pick)
function editRow(row, { ctrlKey = false, hide = false } = {}) {
  Plot.edit({
    curData: row,
    allData: plotData.value,
    multiEdit: ctrlKey,       // Ctrl 多选编辑
    hide,                     // true 时隐藏编辑点
    moveMultiple: true,       // 整体移动
    insertPoint: true,        // 边中点虚拟点
    enableSnap: true,
    snapConfig: {
      snapDistance: 20,
      snapTypes: ['vertex', 'edge', 'center'],
      showSnapIndicator: true,
    },
    historyManager: historyManager.value,
  }, () => {
    plotData.value = plotData.value.filter((o) => o.config.objId !== row.config.objId)
  })
}

// 撤回 / 重做
const { canUndo, canRedo } = Plot.getUndoRedoState(historyManager.value)

async function undo() {
  await Plot.simpleUndo(historyManager.value, plotData, showData, clearAll)
}

async function redo() {
  await Plot.simpleRedo(historyManager.value, plotData, showData, clearAll)
}

function clearAll() {
  plotData.value.forEach((item) => Plot.clear(item.config.objId))
}

Plot.edit 参数

| 参数 | 说明 | |------|------| | curData | 当前编辑的标绘数据 | | allData | 全部标绘列表(删除时用) | | moveMultiple | 启用整体移动 | | insertPoint | 边中点虚拟点,可拖动插入顶点 | | multiEdit | Ctrl 多选模式 | | enableSnap | 顶点吸附 | | snapConfig | 吸附距离、类型等 | | historyManager | 历史记录管理器,拖动/删除自动入栈 | | hide | 隐藏编辑控制点 |

Plot 多边形静态方法

| 方法 | 说明 | |------|------| | Plot.performPolygonSplit | 折线分割多边形 | | Plot.performPolygonUnion | 合并多个多边形 | | Plot.performCoverageDelete | 覆盖删除 | | Plot.createHistoryManager | 创建历史管理器 | | Plot.executeWithHistory | 包装操作并自动保存历史 | | Plot.simpleUndo / Plot.simpleRedo | 撤回 / 重做 | | Plot.getUndoRedoState | 获取按钮可用状态 |

常用 typedrawPointlinepolygonbrokenLine(分割线)、rectcirclearrow 等,完整列表见 plotConfig


map 工具

import { map, mapConfig } from 'ux-cesium'

// 初始化地图
map.initCesiumMap({ ...mapConfig.mapProviderConfig[1], extendConfig: {} }, 1, () => {
  // viewer 就绪回调
})

map.flyTo({ lng: 114.2, lat: 22.5, height: 5000 })

filterMap 底图滤镜

import { filterMap } from 'ux-cesium'

filterMap(window.viewer, {
  invertColor: true,
  filterRGB: [60, 145, 172],
  brightness: 0.6,
  contrast: 1.8,
})

keyboardMapRoamingInit

| 按键 | 功能 | |------|------| | W / S / A / D | 前 / 后 / 左 / 右 | | Q / E | 升 / 降 | | ↑ ↓ ← → | 抬头 / 低头 / 左转 / 右转 | | + / - | 放大 / 缩小 |


本地开发

pnpm install
pnpm dev      # 演示项目(PlotPanel / PolygonEdit 组件)
pnpm build    # 打包库(入口 src/lib/main.ts)

目录

src/
├── lib/main.ts              # 库导出入口
├── plot/                    # 标绘、点位、聚合
├── map/                     # 地图工具与配置
└── components/
    ├── PlotPanel.vue        # 基础标绘演示
    └── PolygonEdit.vue      # 多边形分割/合并/历史记录演示