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

@microclear/label-image

v0.1.1

Published

Pure frontend JS library with Vue 3 demo and Vite build.

Readme

ImageLabel

一个纯前端标注引擎,提供:

  • 基础标注能力:dot / line / polygon / circle / ellipse
  • 编辑能力:选中、拖点、拖整图形、插点、删点、删除、清空
  • 批量删点能力:line / polygon 支持单击切换端点、框选端点、Enter 确认删除、Esc 退出回滚
  • 视口能力:缩放、平移、resize 后保持标注相对图片位置不变
  • 历史能力:撤销/重做(双栈模型)
  • 数据能力:按图片归一化坐标导入/导出
  • 可见性能力:单个/批量/全量显示隐藏(默认不直接写入 history)

项目同时包含一个 Vue 3 Demo 页面(src/demo),用于联调和功能验证。

当前状态(TS Migration)

  • 库核心与特性模块已迁移为 TypeScript(含 core / model / features)。
  • Demo 已启用 TS:
    • src/demo/App.vue 使用 <script setup lang="ts">
    • src/demo/main.ts 为入口文件
  • 类型声明通过 vite-plugin-dts 生成,类型入口为 dist/lib/types/index.d.ts

环境与命令

安装

npm install

本地开发

npm run dev

构建

npm run build:lib
npm run build:demo
npm run build

类型检查与类型覆盖率

npm run typecheck
npm run type-coverage
npm run type-coverage:check

代码格式化

npm run prettier
npm run prettier:check

目录结构

src/
  lib/
    image-label/           # 标注引擎核心实现
  demo/                    # Vue 3 Demo
dist/                      # 构建产物
vite.lib.config.ts
vite.demo.config.ts

快速开始

import { createImageLabel, EVENTS } from '@microclear/label-image';

const image = new Image();
image.src = '/demo.jpg';
await image.decode();

const engine = createImageLabel({
  layout: {
    container: document.getElementById('host'),
    width: 960,
    height: 560,
  },
  image: {
    image, // 必填
  },
  viewport: {
    viewportHotkey: 'ctrl-meta',
  },
  interaction: {
    rightClickActivateMarkItem: true,
  },
});

engine.on(EVENTS.COMPLETE_EDIT_ITEM, () => {
  console.log('编辑完成', engine.getMarkData());
});

初始化配置

createImageLabel(options) 仅接受结构化配置(EngineInitOptions),不再兼容旧平铺字段。

| 命名空间 | 关键字段 | 默认值 | 说明 | | --- | --- | --- | --- | | layout | container(必填), width, height | 800/600 | 画布挂载容器与尺寸 | | image | image(必填), imageRect, imageBrightness, imageContrast | null/100/100 | 底图与视觉参数 | | viewport | minScale, maxScale, zoomFactor, viewportHotkey, keyPanStep | 0.2/5/1.1/ctrl-meta/20 | 视口缩放平移参数 | | edit | minCircleRadius, minEllipseA, minEllipseB, dotRadius, magneticPolicy | 5/5/5/5/{} | 创建约束与磁性策略 | | interaction | rightClickActivateMarkItem | true | 右键命中标注本体时是否自动激活 | | style | markDefaultStyle, highlightVisualStyle | 见内置默认值 | 全局绘制与高亮样式 | | history | historyMaxLength | 100 | 撤销/重做栈最大长度 |

对外 API

生命周期与事件

  • on(eventName, handler)
  • off(eventName, handler)
  • destroy()

模式与编辑权限

  • setMode(mode) // 建议配合 MODES 常量:CREATE / EDIT / READONLY
  • enableEdit()
  • disableEdit()

视口与坐标

  • resize(width, height)
  • zoomIn(anchor?)
  • zoomOut(anchor?)
  • move(dx, dy)
  • toCanvasPos(point)
  • toCanvasPosInner(point)
  • toGlobalPos(point)
  • canvasToImagePoint(point)
  • imageToCanvasPoint(point)

图片相关

  • refreshImage({ image?, imageBrightness?, imageContrast?, forceRefresh? })
  • initImageSession({ image?, cvScriptUrl? }) // 预热磁力剪刀 image session(对应 init-image-session
  • updateOpt(nextOpt)
  • isImageReady()
  • getImageRect()
  • getImageSourceSize()

自动识别与框选

  • pickRect(options?) // 启动一次框选会话,返回 canvas/global/image 三套坐标结果
  • autoDetectBorderAtPoint(point, options?) // 点击点附近自动识别边框并创建 polygon
  • autoDetectBorderInRect(rect, options?) // 框选区域内自动识别边框并创建 polygon

标注创建与编辑

  • createMarkItem(type, options?)
  • activateMarkItem(id)
  • deActivateMarkItem()
  • getMarkItemById(id, options?)
  • updateMarkItem(id, patch, options?)
  • updateCurrentPoint(pointIndex, point)
  • removeCurrentPoint(pointIndex)
  • moveCurrentItem(dx, dy)
  • completeCurrentItem()
  • exitCreate()
  • deleteMarkItem(id)
  • deleteAllMarkItem()
  • reset()
  • getState()
  • activateBatchDeletePoints() // 激活批量删点模式(仅 line/polygon)
  • deactivateBatchDeletePoints(options?) // 退出批量删点,{ restore: true } 可回滚
  • isBatchDeletePointsActive() // 查询批量删点模式状态
  • confirmBatchDeletePoints() // 确认删除已激活端点

createMarkItem 中与磁力剪刀相关的 options

  • magnetic?: booleantype="line" / type="polygon" 生效,开启后使用磁性吸附路径创建。
  • magneticPolicy?: { maxPathPoints?: number; cvScriptUrl?: string; preset?: string }
    • maxPathPoints:预览路径最大采样点数,默认 128
    • cvScriptUrl:OpenCV.js 地址,默认 '/vendor/opencv/opencv.js'

批量删点补充说明:

  • 仅在“非创建态 + 当前激活项是 line/polygon”时可激活。
  • 激活态端点为红色高亮;支持单击切换与框选激活。
  • confirmBatchDeletePoints() 返回 { ok, reason, removedCount },失败时可根据 reason 做提示。
  • 删除过程会执行最小端点数量校验与自交校验,校验失败不会落库。
  • 调用 createMarkItem(...) 开始新建时,会自动退出批量删点(回滚未确认修改)。
  • 可配合 BATCH_DELETE_POINTS_STATE_CHANGE / BATCH_DELETE_POINTS_CONFIRM 做 UI 与提示联动。

标注可见性

  • setMarkVisible(id, visible)
  • setMarkVisibleBatch(ids, visible)
  • setAllMarkVisible(visible)
  • bringMarkItemToFront(id) // 置顶
  • sendMarkItemToBack(id) // 置底

层级规则备注:

  • 标注层级由数组顺序决定:index 越大,层级越高(越靠上显示)。
  • 命中查找按层级从高到低执行,重叠区域优先选中上层标注。

数据导入导出

  • getMarkData()
  • reShow(serialized)
  • getExportCanvas() // 返回当前可导出的画布(分层渲染时会先合成)
  • exportImage(options?)
  • exportImageOrigin(options?)
  • exportImageWithMarksOrigin(options?) // 原图尺寸 + 含标注

导出备注:

  • exportImage:导出当前画布(含标注),输出尺寸=当前画布尺寸。
  • exportImageOrigin:导出原图(不含标注),仅当底图对象支持 toDataURL 时可用。
  • exportImageWithMarksOrigin:导出原图尺寸且包含标注。
  • exportImageWithMarksOrigin 默认会按“当前画布显示比例(含 zoom)”自动调整标注线宽/点半径。
  • 如需手动调整导出粗细,可传 styleScale 覆盖自动比例:exportImageWithMarksOrigin({ styleScale: 1.5 })

磁力剪刀(Magnetic Line/Polygon)

磁力剪刀基于 OpenCV IntelligentScissors,用于沿图像边缘自动吸附线段/多边形路径。

使用前准备:

  1. 确保 OpenCV 资源可访问(默认路径):
    • public/vendor/opencv/opencv.js
    • public/vendor/opencv/opencv_js.wasm
  2. 若你使用自定义静态资源路径,请在 magneticPolicy.cvScriptUrl 传入对应地址。

创建示例:

engine.createMarkItem('polygon', {
  magnetic: true,
  magneticPolicy: {
    maxPathPoints: 128,
    cvScriptUrl: '/vendor/opencv/opencv.js',
  },
  props: {
    lineWidth: 2,
  },
});

也可用于 line

engine.createMarkItem('line', {
  magnetic: true,
  magneticPolicy: {
    maxPathPoints: 128,
    cvScriptUrl: '/vendor/opencv/opencv.js',
  },
});

交互说明:

  • 首次点击设置锚点。
  • 鼠标移动时显示“锚点 -> 当前点”的吸附预览路径。
  • 再次点击会按预览路径追加多段点。
  • 靠近首点点击可闭合;也可按 Enter 完成当前标注,按 Esc 取消当前创建。

降级行为:

  • 若当前环境不支持或 OpenCV 初始化失败,路径会自动回退为“锚点到目标点直线”,不阻断标注流程。

历史(Undo/Redo)

  • canUndo()
  • canRedo()
  • undo()
  • redo()
  • clearHistory()

模式常量(MODES)

  • MODES.CREATE
  • MODES.EDIT
  • MODES.READONLY

事件列表(EVENTS)

输入与交互

  • CLICK
  • MOUSEDOWN
  • MOUSEMOVE
  • MOUSEUP
  • MOUSELEAVE
  • CONTEXTMENU
  • WHEEL
  • ESCAPE
  • ENTER_KEY
  • DELETE_KEY
  • UNDO_REQUEST
  • REDO_REQUEST
  • ARROW_PAN
  • WINDOW_BLUR
  • VIEWPORT_HOTKEY_CHANGE
  • CANVAS_DRAG_STATE_CHANGE
  • ITEM_DRAG_STATE_CHANGE

状态与渲染

  • RESIZE
  • MODE_CHANGE
  • TRANSFORM
  • SCALE_CHANGE
  • CURSOR_CHANGE
  • HOVER_TARGET_CHANGE
  • UPDATED_OPT
  • IMAGE_READY
  • IMAGE_CONFIG_APPLIED
  • IMAGE_REQUIRED
  • DESTROY

标注业务事件

  • CURRENT_MARK_ITEM_CHANGE
  • IS_CREATE_MARKING_CHANGE
  • COMPLETE_CREATE_ITEM
  • COMPLETE_EDIT_ITEM
  • LINE_CROSS
  • POLYGON_CLOSE_HINT
  • DELETE_MARKING_ITEM
  • DELETE_ALL_MARKING_ITEM
  • BATCH_DELETE_POINTS_STATE_CHANGE
  • BATCH_DELETE_POINTS_CONFIRM

历史事件

  • HISTORY_CHANGE
  • UNDO
  • REDO

框选事件

  • RECT_PICK_START
  • RECT_PICK_CHANGE
  • RECT_PICK_END
  • RECT_PICK_CANCEL

新增:批量删点事件

  • BATCH_DELETE_POINTS_STATE_CHANGE
    • 触发时机:进入/退出批量删点模式
    • 事件载荷:
      • active: 是否处于批量删点模式
      • restore: 退出时是否执行了回滚
      • reason: 状态变化原因(如 activate / api / create-item / escape / window-blur / mode-change / disable-edit / confirm-success
      • itemId: 对应标注 id(若可解析)
      • selectedCount: 当前激活端点数量
  • BATCH_DELETE_POINTS_CONFIRM
    • 触发时机:调用 confirmBatchDeletePoints() 后(成功/失败都会触发)
    • 事件载荷:
      • ok: 是否确认删除成功
      • reason: 结果原因(如 ok / empty-selection / min-point / invalid-shape / session-inactive
      • removedCount: 实际删除端点数量
      • itemId: 对应标注 id(若可解析)

新增:激活态标注右击事件

  • ACTIVE_MARK_ITEM_CONTEXTMENU
    • 触发条件:仅在“当前激活标注”上右击命中时触发(命中本体与端点都会触发)
    • 事件载荷:
      • markItem: 当前激活标注(序列化对象)
      • canvasPoint: 鼠标的 canvas 坐标 { x, y }
      • hit: 命中信息 { pointIndex, segmentIndex }(命中端点时 pointIndex >= 0

示例:

engine.on(EVENTS.ACTIVE_MARK_ITEM_CONTEXTMENU, ({ markItem, canvasPoint, hit }) => {
  // 可用于区分“命中端点”和“命中图形本体”,在菜单中按需显示“删除端点”
  console.log('右击激活标注', markItem.id, canvasPoint, hit);
});

标注数据格式

getMarkData() 返回数组,每个元素结构如下。

type MarkData = {
  id: string | number;
  type: 'dot' | 'line' | 'polygon' | 'circle' | 'ellipse';
  pointArr: Array<{ x: number; y: number }>; // 图片归一化坐标(0~1)
  magnetic?: boolean; // 可选,line / polygon 可能出现
  magneticPolicy?: { maxPathPoints?: number; cvScriptUrl?: string; preset?: string } | null; // 可选
  props: Record<string, any>;
  data: Record<string, any>;
  visible: boolean; // 必填
};

说明:

  • pointArr 在导出时是图片归一化坐标,不是运行时画布像素坐标。
  • reShow 仅接受包含 visible 的数据;缺失会抛错。
  • 不兼容不带 visible 的旧数据结构。

历史行为说明

  • 历史采用双栈(undoStack / redoStack)。
  • image 切换时会清空历史栈(避免跨图回退污染)。
  • resize 不进入 undo/redo。
  • setMarkVisible* 方法默认不直接调用 recordHistory
  • 但历史快照当前包含 visible 字段,后续其他会入栈操作发生时,visible 状态会随快照进入历史。

坐标与 resize 约定

  • 运行时编辑坐标基于画布内部坐标。
  • 导入导出坐标基于图片归一化坐标(0~1)。
  • 画布 resize 后会按图片归一化位置重映射标注,保持“标注在图片上的相对位置不变”。

Demo

  • Demo 入口:src/demo/main.ts
  • Demo 主页面:src/demo/App.vue
  • 样式:src/demo/style.css
  • 功能覆盖:创建/编辑、批量删点、右键菜单(置顶/置底/删除)、视口、自动识别、JSON 回显、导出、可见性测试、事件联动日志

包入口导出

@microclear/label-image 入口可直接使用:

  • createImageLabel
  • ImageLabelEngine
  • EVENTS
  • MODES
  • initImageSession // 包级预热能力(不依赖 engine 实例)
  • isMagneticScissorsSupported
  • isWasmSupported
  • isWgpuSupported
  • formatLabel
  • createLabelStats

类型入口

  • npm 包 package.json 中:
    • "types": "./dist/lib/types/index.d.ts"
  • 生成声明前建议先执行:
    • npm run build:lib