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

@4xian/vue-fabric

v1.0.0

Published

基于 fabric.js 的二次封装绘图工具库,支持任意区域画图(直线,曲线),矩形,文本,图片等功能,不限制框架,原生js可使用。

Readme

@4xian/vue-fabric

基于 fabric.js v6 的高层绘图工具库,提供开箱即用的 Canvas 绘图 SDK。

无框架依赖,支持 Vue、React、原生 JavaScript 等任意环境。

特性

  • 多种绘图工具:选择、拖拽、直线、多边形区域、曲线、矩形、文本、图片
  • 内置 UI 组件:可拖拽工具栏 + HSV 颜色选择器(纯原生 DOM,无框架依赖)
  • 完整撤销/重做:基于 JSON 快照,支持暂停/恢复历史记录
  • 画布缩放与平移:鼠标滚轮缩放、Alt/中键拖拽,支持缩放原点配置
  • 背景图支持:fill / fit / stretch / center / repeat 五种模式,跟随缩放自动更新
  • 人员追踪:实时位置显示、平滑移动动画、状态涟漪效果、轨迹路径展示
  • 导出能力:JSON / PNG / JPEG / WebP / SVG,支持自动下载
  • Retina 屏支持:自动检测 devicePixelRatio
  • 自动响应式尺寸ResizeObserver 自动缩放适配
  • 完整 TypeScript 类型定义

安装

# npm
npm install @4xian/vue-fabric fabric

# pnpm
pnpm add @4xian/vue-fabric fabric

# yarn
yarn add @4xian/vue-fabric fabric

fabric 是对等依赖(peerDependency),需要单独安装,要求版本 ^6.0.0

快速开始

Vue 3

<template>
  <div ref="container" class="canvas-container"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import PaintBoard, {
  SelectTool,
  DragTool,
  LineTool,
  AreaTool,
  CurveTool,
  RectTool,
  TextTool,
  ImageTool,
  Toolbar
} from '@4xian/vue-fabric'
import '@4xian/vue-fabric/style.css'

const container = ref(null)
let paintBoard = null
let toolbar = null

onMounted(() => {
  paintBoard = new PaintBoard(container.value, {
    width: 1200,
    height: 800,
    backgroundColor: '#ffffff'
  }).init()

  paintBoard
    .registerTool('select', new SelectTool())
    .registerTool('drag', new DragTool())
    .registerTool('line', new LineTool())
    .registerTool('area', new AreaTool({ enableFill: true }))
    .registerTool('curve', new CurveTool())
    .registerTool('rect', new RectTool())
    .registerTool('text', new TextTool())
    .registerTool('image', new ImageTool())
    .setTool('select')

  toolbar = new Toolbar(paintBoard).init()

  paintBoard.on('line:created', data => {
    console.log('直线创建:', data.drawId, data.distance)
  })

  paintBoard.on('area:created', data => {
    console.log('区域创建:', data.drawId, data.points)
  })
})

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

<style scoped>
.canvas-container {
  width: 100%;
  height: 600px;
  position: relative;
}
</style>

原生 JavaScript(UMD)

<link rel="stylesheet" href="node_modules/@4xian/vue-fabric/dist/style.css" />
<div id="canvas-container"></div>

<script src="node_modules/fabric/dist/fabric.js"></script>
<script src="node_modules/@4xian/vue-fabric/dist/vue-fabric.umd.js"></script>
<script>
  const { PaintBoard, SelectTool, LineTool, AreaTool, Toolbar } = VueFabric

  const board = new PaintBoard(document.getElementById('canvas-container'), {
    width: 1200,
    height: 800
  }).init()

  board
    .registerTool('select', new SelectTool())
    .registerTool('line', new LineTool())
    .registerTool('area', new AreaTool())
    .setTool('select')

  new Toolbar(board).init()
</script>

ESM 模块

import PaintBoard, { SelectTool, LineTool, AreaTool } from '@4xian/vue-fabric'
import '@4xian/vue-fabric/style.css'

const board = new PaintBoard('#canvas-container', {
  width: 1200,
  height: 800
}).init()

board
  .registerTool('select', new SelectTool())
  .registerTool('line', new LineTool())
  .registerTool('area', new AreaTool())
  .setTool('select')

API 参考

PaintBoard

主画板类,所有功能的入口。

构造函数

new PaintBoard(container: HTMLElement | string, options?: FabricPaintOptions)

配置项(FabricPaintOptions):

| 属性 | 类型 | 默认值 | 说明 | | ------------------------ | ---------------------------------- | -------------------------- | ------------------------------- | | width | number | 1200 | 画布宽度 | | height | number | 800 | 画布高度 | | backgroundColor | string | 'transparent' | 背景颜色 | | backgroundImage | string \| BackgroundImageOptions | - | 背景图配置 | | lineColor | string | 'rgba(2, 167, 240, 1)' | 默认线条颜色 | | fillColor | string | 'rgba(128, 255, 255, 1)' | 默认填充颜色 | | pixelRatio | number \| 'auto' | 'auto' | 像素比('auto' 自动检测 DPR) | | autoResize | boolean | false | 是否启用自动响应式尺寸 | | selection | boolean | true | 启用框选 | | preserveObjectStacking | boolean | true | 保持对象层级 | | perPixelTargetFind | boolean | false | 像素级碰撞检测 |

工具管理

board.registerTool(name, toolInstance) // 注册工具,返回 this
board.setTool(name) // 切换工具,返回 this
board.getCurrentTool() // 获取当前工具名称

颜色设置

board.setLineColor(color) // 设置线条颜色,返回 this
board.setFillColor(color) // 设置填充颜色,返回 this

缩放控制

board.zoomIn() // 放大(默认步长 1.1x)
board.zoomOut() // 缩小
board.resetZoom() // 重置为 100%
board.setZoom(value) // 设置指定缩放值(0.2 ~ 5)
board.getZoom() // 获取当前缩放值
board.fitZoom() // 适配画布到容器大小

撤销/重做

board.undo() // 撤销,返回 boolean
board.redo() // 重做,返回 boolean
board.canUndo() // 是否可撤销,返回 boolean
board.canRedo() // 是否可重做,返回 boolean
board.pauseHistory() // 暂停历史记录
board.resumeHistory() // 恢复历史记录

背景图

// 支持 URL 或 base64
board.setBackgroundImage(source, options)
board.clearBackgroundImage()

// options 配置项:
// { mode: 'fill' | 'fit' | 'stretch' | 'center' | 'repeat' }

导出与导入

// JSON 序列化
const json = board.exportToJSON()
await board.importFromJSON(json)

// 图片导出
board.exportToImage({
  format: 'png', // 'png' | 'jpeg' | 'webp'
  quality: 100, // 0-100
  multiplier: 2, // 分辨率倍数
  download: true, // 是否触发下载
  filename: 'canvas' // 文件名(不含扩展名)
})

// SVG 导出
const svgStr = board.exportToSVG()

数据查询

board.getAreasData() // 获取所有区域数据
board.getTextsData() // 获取所有文本数据
board.getCustomObjects() // 获取所有自定义对象(含直线/曲线/矩形等)
board.getObjectById(id) // 按 ID 获取 fabric 对象

对象操作

// 添加文本(编程方式,不依赖工具)
board.addText({ x, y, text, fontSize, fill, id })
board.insertText({ x, y, text, fontSize, fill, id })     // 不触发历史记录

// 添加图片
board.addImage({ x, y, src, width, height, angle, opacity, id })
board.insertImage({ x, y, src, ... })

// 批量操作
board.batchInsertTexts(textsArray)
board.batchInsertImages(imagesArray)
board.batchRemoveByIds(idsArray)

// 删除
board.removeById(id)

// 更新文本内容
board.updateTextById(id, options)

辅助元素控制

board.showAllAreaHelpers() // 显示所有区域的距离标签和辅助点
board.hideAllAreaHelpers() // 隐藏所有辅助元素
board.toggleAreaHelpers() // 切换显示/隐藏

调整大小

board.resize(width, height) // 手动调整画布大小
board.enableAutoResize() // 启用 ResizeObserver 自动响应
board.disableAutoResize() // 禁用自动响应

其他

board.clear() // 清空画布
board.destroy() // 销毁,释放资源
board.getCanvas() // 获取原始 fabric.Canvas 实例
board.on(event, callback) // 监听事件
board.off(event, callback) // 取消监听

绘图工具

所有工具继承自 BaseTool,通过 registerTool() 注册后由 setTool() 激活。

SelectTool(选择工具)

点击选择对象,框选多个,Delete / Backspace 删除选中对象。

const selectTool = new SelectTool()
board.registerTool('select', selectTool)

DragTool(拖拽工具)

按住 Ctrl / Meta 键拖拽移动整个画布视口。

const dragTool = new DragTool()
board.registerTool('drag', dragTool)

LineTool(直线工具)

两次点击绘制直线,自动计算并显示距离标签。

const lineTool = new LineTool({
  pointRadius: 3, // 端点圆圈半径
  labelFontSize: 12 // 距离标签字号
})
board.registerTool('line', lineTool)

快捷键: ESC 取消当前绘制

事件数据(drawId 代替旧版 lineId):

{
  drawId: string
  startPoint: {
    x: number
    y: number
  }
  endPoint: {
    x: number
    y: number
  }
  distance: number
  lineColor: string
}

AreaTool(区域工具)

点击添加顶点,靠近起点自动闭合,生成多边形。

const areaTool = new AreaTool({
  closeThreshold: 8, // 闭合距离(px)
  pointRadius: 3, // 顶点半径
  labelFontSize: 12, // 距离标签字号
  enableFill: true, // 启用填充
  allowOverlap: true, // 允许在已有区域内绘制
  defaultShowHelpers: true // 初始显示辅助元素
})
board.registerTool('area', areaTool)

快捷键: ESC 取消,Ctrl+Z 撤销上一个点

事件数据(drawId 代替旧版 areaId):

{
  drawId: string
  points: Array<{ x: number; y: number }>
  distances: number[]
  lineColor: string
  fillColor: string
}

CurveTool(曲线工具)

点击添加控制点,使用 Catmull-Rom 样条生成平滑曲线。

const curveTool = new CurveTool({
  tension: 0.5, // 样条张力(0-1)
  pointRadius: 3,
  closeThreshold: 8,
  enableFill: true
})
board.registerTool('curve', curveTool)

快捷键: Enter 完成开放曲线,ESC 取消,靠近起点自动闭合

事件数据(drawId 代替旧版 curveId):

{
  drawId: string
  points: Array<{ x: number; y: number }>
  isClosed: boolean
  lineColor: string
  fillColor: string
}

RectTool(矩形工具)

点击起点后移动鼠标实时预览,再次点击完成矩形。

const rectTool = new RectTool({
  enableFill: true,
  cornerStyle: 'circle', // 控制点样式
  cornerSize: 8,
  cornerColor: '#ffffff'
})
board.registerTool('rect', rectTool)

事件数据:

{
  drawId: string
  startPoint: {
    x: number
    y: number
  }
  endPoint: {
    x: number
    y: number
  }
  width: number
  height: number
  lineColor: string
  fillColor: string
}

TextTool(文本工具)

点击画布创建可编辑文本,自动进入编辑模式,空文本退出时自动删除。

const textTool = new TextTool()
board.registerTool('text', textTool)

// 编程方式添加文本(不需要激活工具)
board.addText({
  x: 100,
  y: 100,
  text: '示例文本',
  fontSize: 16,
  fill: '#ff0000',
  fontFamily: 'Arial',
  id: 'my-text-1' // 可选,指定自定义 ID
})

ImageTool(图片工具)

支持 URL 和 base64 两种图片来源,可通过文件对话框选取。

const imageTool = new ImageTool()
board.registerTool('image', imageTool)

// 打开文件选择对话框
imageTool.openFileDialog()

// 编程方式添加图片
board.addImage({
  x: 200,
  y: 200,
  src: '/path/to/image.png', // URL 或 base64
  width: 100,
  height: 100,
  angle: 0,
  opacity: 1,
  id: 'my-image-1'
})

快捷键总览

| 工具 | 快捷键 | 说明 | | ---------- | ---------------------- | ---------------- | | SelectTool | Delete / Backspace | 删除选中对象 | | LineTool | ESC | 取消当前绘制 | | AreaTool | ESC | 取消绘制 | | AreaTool | Ctrl+Z | 撤销上一个顶点 | | CurveTool | Enter | 完成开放曲线 | | CurveTool | ESC | 取消绘制 | | CurveTool | Ctrl+Z | 撤销上一个控制点 |


事件系统

通过 board.on(event, callback) 监听,board.off(event, callback) 取消监听。

绘图对象事件

| 事件名 | 数据 | 说明 | | ---------------- | ----------------------------------------------------------------------- | -------------- | | line:created | { drawId, startPoint, endPoint, distance, lineColor } | 直线绘制完成 | | line:selected | 同上 | 直线被选中 | | line:clicked | 同上 | 直线被点击 | | area:created | { drawId, points, distances, lineColor, fillColor } | 区域完成 | | area:clicked | 同上 | 区域被点击 | | area:selected | 同上 | 区域被选中 | | curve:created | { drawId, points, isClosed, lineColor, fillColor } | 曲线完成 | | curve:clicked | 同上 | 曲线被点击 | | curve:selected | 同上 | 曲线被选中 | | rect:created | { drawId, startPoint, endPoint, width, height, lineColor, fillColor } | 矩形完成 | | rect:clicked | 同上 | 矩形被点击 | | text:created | { drawId, text } | 文本创建 | | text:changed | { drawId, text } | 文本内容变化 | | text:clicked | { drawId, text, object } | 文本被点击 | | text:selected | 同上 | 文本被选中 | | text:updated | { id, textObj } | 文本被编程更新 | | image:created | ImageCustomData | 图片创建 | | image:clicked | { id, object } | 图片被点击 | | image:selected | { type, id, object } | 图片被选中 | | image:modified | { id, object } | 图片被修改 | | image:updated | { id, obj } | 图片被编程更新 |

画布与系统事件

| 事件名 | 数据 | 说明 | | ------------------------- | ----------------------------------- | ---------------- | | tool:changed | 工具名称字符串 | 工具切换 | | history:changed | { canUndo, canRedo } | 历史状态变化 | | object:selected | 选中对象数组 | 任意对象选中 | | object:created | fabric 对象 | 对象添加到画布 | | object:modified | fabric 对象 | 对象被修改 | | object:removed | { id, type } | 对象被删除 | | objects:deleted | 删除数量 | 选择工具批量删除 | | canvas:zoomed | 缩放比例 | 画布缩放 | | canvas:panned | - | 画布平移完成 | | canvas:cleared | - | 画布清空 | | canvas:loaded | - | JSON 导入完成 | | canvas:expanded | { width, height } | 画布尺寸扩展 | | canvas:resized | { width, height, scaleX, scaleY } | 画布调整大小 | | backgroundImage:set | { source } | 背景图设置成功 | | backgroundImage:cleared | - | 背景图清除 | | backgroundImage:error | { source } | 背景图加载失败 | | areaHelpers:shown | - | 辅助元素显示 | | areaHelpers:hidden | - | 辅助元素隐藏 | | mouse:move | { x, y } | 鼠标在画布移动 | | batch:textsInserted | { successCount, failedCount } | 批量文字插入完成 | | batch:imagesInserted | { successCount, failedCount } | 批量图片插入完成 | | batch:removed | { removedCount, notFoundCount } | 批量删除完成 |


Toolbar(工具栏)

内置可拖拽工具栏,纯原生 DOM 实现。

import { Toolbar } from '@4xian/vue-fabric'

const toolbar = new Toolbar(paintBoard, {
  tools: [
    'lineColor',
    'fillColor',
    'select',
    'drag',
    'line',
    'area',
    'curve',
    'rect',
    'text',
    'image',
    'undo',
    'redo',
    'zoomIn',
    'zoomOut',
    'fitZoom',
    'download',
    'helpers'
  ],
  visible: true,
  draggable: true // 允许拖拽移动工具栏
})
toolbar.init()

// 销毁
toolbar.destroy()

支持的工具按钮:

| 按钮名 | 功能 | | ----------- | ---------------- | | lineColor | 线条颜色选择器 | | fillColor | 填充颜色选择器 | | select | 选择工具 | | drag | 拖拽工具 | | line | 直线工具 | | area | 区域工具 | | curve | 曲线工具 | | rect | 矩形工具 | | text | 文本工具 | | image | 图片工具 | | undo | 撤销 | | redo | 重做 | | zoomIn | 放大 | | zoomOut | 缩小 | | fitZoom | 适配缩放 | | download | 下载为 PNG | | helpers | 切换距离标签显示 |


ColorPicker(颜色选择器)

纯原生 DOM 实现的 HSV 颜色选择器,支持 RGBA / RGB / HEX 格式输入。

import { ColorPicker } from '@4xian/vue-fabric'

const picker = new ColorPicker({
  defaultColor: 'rgba(255, 0, 0, 1)',
  onChange: color => console.log(color)
})

picker.show() // 显示
picker.hide() // 隐藏
picker.toggle() // 切换显示/隐藏
picker.setColor('#00ff00') // 设置颜色
picker.getColor() // 获取当前颜色字符串
picker.getElement() // 获取 DOM 元素
picker.destroy() // 销毁

PersonTracker(人员追踪器)

实时人员位置展示与追踪,支持平滑动画、状态涟漪、路径轨迹。

// 通过 PaintBoard 创建
const tracker = board.createPersonTracker()

// 批量设置人员(自动平滑动画)
tracker.setPersons(
  [
    { id: 'p1', name: '张三', x: 100, y: 100, lineColor: '#ff4444' },
    { id: 'p2', name: '李四', x: 200, y: 150, lineColor: '#44ff44', base64: '...' }
  ],
  {
    deleteOld: true // 自动清除不在新列表中的旧人员
  }
)

// 更新单个人员位置(带平滑移动动画)
tracker.updatePerson('p1', { x: 150, y: 120, status: 'active' })

// 使用 base64 图片作为标记
tracker.createPerson({
  id: 'p3',
  name: '王五',
  x: 300,
  y: 200,
  base64: 'data:image/png;base64,...' // 自定义头像
})

// 批量渲染(分批处理,防止阻塞)
tracker.createMultiplePersons(personsArray, {
  batchSize: 50, // 每批数量
  batchDelay: 16 // 批次间延迟(ms)
})

// 轨迹展示
tracker.createPersonTraces('p1', person, tracePoints, {
  radius: 4,
  pathType: 'curve', // 'line' | 'curve'
  animationSpeed: 2, // 轨迹动画速度
  color: '#ff4444'
})

// 显示/隐藏轨迹
tracker.showTrace('p1')
tracker.hideTrace('p1')

// 移除
tracker.removePerson('p1')
tracker.clearPersons() // 清除所有人员(保留轨迹)
tracker.clearTraces() // 清除所有轨迹(保留人员)
tracker.clearAll() // 清除所有人员和轨迹

人员追踪事件:

| 事件名 | 数据 | 说明 | | --------------------- | ------------ | ------------ | | person:created | PersonData | 人员标记创建 | | person:updated | PersonData | 人员位置更新 | | person:removed | { id } | 人员标记移除 | | person:clicked | PersonData | 人员被点击 | | person:statusChange | PersonData | 人员状态变化 | | persons:cleared | - | 所有人员清除 | | trace:shown | { id } | 轨迹显示 | | trace:hidden | { id } | 轨迹隐藏 | | traces:cleared | - | 所有轨迹清除 |


TypeScript 类型

import type {
  Point,
  FabricPaintOptions,
  CanvasManagerOptions,
  BaseToolOptions,
  AreaToolOptions,
  CurveToolOptions,
  LineToolOptions,
  RectToolOptions,
  TextToolOptions,
  ImageToolOptions,
  AreaCustomData,
  LineCustomData,
  CurveCustomData,
  RectCustomData,
  TextCustomData,
  ImageCustomData,
  PersonData,
  TraceOptions,
  ExportImageOptions,
  ExportJSONOptions,
  AddTextOptions,
  AddImageOptions,
  ToolbarOptions,
  ColorPickerOptions,
  ToolName,
  BatchTextInsertResult,
  BatchImageInsertResult,
  BatchRemoveResult
} from '@4xian/vue-fabric'

构建产物

| 文件 | 格式 | 说明 | | ---------------------------- | ---------- | --------------------------------------- | | dist/vue-fabric.js | ESM | 支持 Tree-shaking,推荐在打包项目中使用 | | dist/vue-fabric.umd.js | UMD | 全局变量 VueFabric,适合 CDN 引入 | | dist/vue-fabric.umd.min.js | UMD 压缩 | 体积更小,需单独引入 CSS | | dist/style.css | CSS | 工具栏和颜色选择器样式 | | dist/index.d.ts | TypeScript | 完整类型声明 |


开发

pnpm install      # 安装依赖
pnpm dev          # 监听模式构建
pnpm build        # 构建生产产物
pnpm demo         # 启动演示服务(端口 3000)
pnpm demo:dev     # 并发运行 dev + demo
pnpm test         # 运行测试(watch 模式)
pnpm test:run     # 单次运行测试
pnpm lint         # ESLint 检查
pnpm lint:fix     # ESLint 自动修复
pnpm format       # Prettier 格式化
pnpm typecheck    # TypeScript 类型检查

提交规范

项目使用 Conventional Commits 规范,通过 commitlint 强制执行。

git commit -m "feat: 添加新功能"
git commit -m "fix: 修复某个 bug"
git commit -m "docs: 更新文档"

许可证

MPL-2.0