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

@knotx/plugins-selection

v0.5.8

Published

Selection Plugin for Knotx

Readme

@knotx/plugins-selection

选择插件,为 KnotX 提供元素选择功能。

安装

npm install @knotx/plugins-selection

概述

Selection 插件为 KnotX 提供了强大的元素选择功能,支持鼠标框选、键盘操作和程序化选择。该插件基于 @knotx/viselect 库实现,提供了灵活的选择规则和丰富的选择事件。

实现原理

Selection 插件的核心实现原理:

  1. 选择区域管理:使用 @knotx/viselect 库创建选择区域,支持拖拽选择
  2. 规则系统:通过规则系统定义不同类型元素的选择行为
  3. 事件处理:提供完整的选择事件生命周期管理
  4. 状态同步:与画布变换状态同步,确保选择区域的准确性

依赖关系

核心依赖

  • @knotx/core:提供基础插件架构
  • @knotx/decorators:提供装饰器支持
  • @knotx/viselect:提供选择区域功能

插件依赖

  • @knotx/plugins-canvas:获取画布变换状态和容器信息(可选)

API 文档

主要类

Selection

选择插件的主要类,继承自 BasePlugin

export class Selection extends BasePlugin<'selection', SelectionConfig> {
  name = 'selection' as const
}

配置选项

SelectionConfig

export interface SelectionConfig {
  /** 选择区域的类名 */
  selectionAreaClassName?: string
  /** 是否启用拖拽选择 */
  enableDrag?: boolean
  /** 选择规则 */
  rules?: SelectionRule[]
  /** 是否禁用默认规则 */
  disableDefaultRules?: boolean
  /** 选择容器 */
  container?: string
}

SelectionRule

export interface SelectionRule {
  /** 资源类型 */
  type: string
  /** 元素的类名 */
  className: string
  /** ID 获取函数 */
  idGetter: (element: Element) => string
  /** 激活状态的类名 */
  activeClassName?: string
  /** 选择回调函数 */
  onSelected?: (context: SelectionContext) => boolean
  /** 数据选择器类型 */
  dataSelectorType?: string
  /** 是否启用规则 */
  enabled?: boolean
}

插件数据 (PluginData)

Selection 插件提供以下数据:

interface PluginData {
  selection: {
    selected: SelectionSelectedItem[]
    registerRules: (rules: SelectionRule[]) => () => void
    setRuleEnabled: (type: string, enabled: boolean) => void
    setClearSelectionBeforeStart: (isClearSelectionBeforeStart: boolean) => void
    setElementOverlap: (overlap: OverlapMode) => void
    resolveSelectables: () => void
  }
}

插件工具 (PluginTools)

Selection 插件提供以下工具方法:

interface PluginTools {
  selection: {
    select: (items: SelectionSelectedItem[]) => void
    deselect: (items: SelectionSelectedItem[]) => void
    getSelected: () => SelectionSelectedItem[]
    clearSelection: () => void
  }
}

类型定义

SelectionSelectedItem

export interface SelectionSelectedItem {
  type: string
  id: string
}

使用示例

基本用法

import { Selection } from '@knotx/plugins-selection'

const engine = new Engine({
  plugins: [Selection],
  pluginConfig: {
    selection: {
      enableDrag: true,
    },
  },
})

自定义选择规则

const engine = new Engine({
  plugins: [Selection],
  pluginConfig: {
    selection: {
      rules: [
        {
          type: 'custom-node',
          className: 'custom-node-wrapper',
          idGetter: element => element.getAttribute('data-node-id') || '',
          activeClassName: 'custom-node-selected',
          onSelected: (context) => {
            console.log('Custom node selected:', context.id)
            return true // 返回 true 表示允许选择
          },
        },
      ],
    },
  },
})

程序化选择

// 选择特定元素
engine.callTool('selection', 'select', [
  { type: 'node', id: 'node-1' },
  { type: 'node', id: 'node-2' },
])

// 取消选择特定元素
engine.callTool('selection', 'deselect', [
  { type: 'node', id: 'node-1' },
])

// 获取当前选择的元素
const selected = engine.callTool('selection', 'getSelected')
console.log('Selected items:', selected)

// 清空所有选择
engine.callTool('selection', 'clearSelection')

动态管理选择规则

// 获取插件数据
const selectionData = engine.getPluginData('selection')

// 注册新规则
const unregister = selectionData.registerRules([
  {
    type: 'edge',
    className: 'edge-wrapper',
    idGetter: element => element.getAttribute('data-edge-id') || '',
    activeClassName: 'edge-selected',
  },
])

// 启用/禁用规则
selectionData.setRuleEnabled('edge', false)

// 设置重叠模式
selectionData.setElementOverlap('invert') // 'keep' | 'drop' | 'invert'

// 取消注册规则
unregister()

监听选择变化

class MyPlugin extends BasePlugin {
  @inject.selection.selected()
  selected!: SelectionSelectedItem[]

  @subscribe.selection.selected()
  onSelectedChange(selected: SelectionSelectedItem[]) {
    console.log('Selection changed:', selected)
  }
}

与 Canvas 插件集成

import { Canvas } from '@knotx/plugins-canvas'
import { Selection } from '@knotx/plugins-selection'

const engine = new Engine({
  plugins: [Canvas, Selection],
  pluginConfig: {
    canvas: {
      minScale: 0.1,
      maxScale: 3,
    },
    selection: {
      enableDrag: true,
      container: '.canvas-container', // 指定选择容器
    },
  },
})

高级功能

自定义选择行为

const engine = new Engine({
  plugins: [Selection],
  pluginConfig: {
    selection: {
      rules: [
        {
          type: 'node',
          className: 'node-wrapper',
          idGetter: element => element.getAttribute('data-node-id') || '',
          onSelected: (context) => {
            const { element, type, id, isDragging, getSelectedElements, select, deselect } = context

            // 自定义选择逻辑
            if (isDragging) {
              // 拖拽选择时的逻辑
              return true
            }

            // 单击选择时的逻辑
            const selectedElements = getSelectedElements()
            if (selectedElements.node && selectedElements.node.length > 0) {
              // 已有选择,执行多选逻辑
              return true
            }

            return true
          },
        },
      ],
    },
  },
})

选择区域样式自定义

const engine = new Engine({
  plugins: [Selection],
  pluginConfig: {
    selection: {
      selectionAreaClassName: 'custom-selection-area',
    },
  },
})
.custom-selection-area {
  background: rgba(74, 144, 226, 0.1);
  border: 2px dashed #4A90E2;
  border-radius: 4px;
}

文件目录结构

packages/plugins-selection/
├── src/
│   ├── selection.tsx           # 主要实现文件
│   └── index.ts               # 导出文件
├── dist/                      # 构建输出目录
├── package.json              # 包配置文件
├── build.config.ts           # 构建配置
├── tsconfig.json             # TypeScript 配置
├── eslint.config.mjs         # ESLint 配置
└── CHANGELOG.md              # 更新日志

核心文件说明

  • selection.tsx:包含 Selection 插件的主要实现,包括选择区域管理、规则系统和事件处理
  • index.ts:导出 Selection 类和相关类型定义

注意事项

  1. 性能考虑:大量元素时,选择操作可能影响性能,建议使用虚拟化或分页
  2. 事件冲突:与其他交互插件(如拖拽)可能存在事件冲突,注意事件优先级
  3. 内存管理:及时清理不需要的选择规则,避免内存泄漏
  4. 浏览器兼容性:依赖现代浏览器的 DOM API,注意兼容性

许可证

MIT