# @sketch-ruler/canvas

> Canvas rendering and DOM input management for sketch-ruler. Framework-agnostic, depends on Canvas 2D API and DOM Events.

Latest version **3.1.6** (published 2026-07-27) · MIT license · 0 weekly downloads

## Install

```sh
npm install @sketch-ruler/canvas
pnpm add @sketch-ruler/canvas
yarn add @sketch-ruler/canvas
bun add @sketch-ruler/canvas
```

## Health

**Score 60/100 (C)** — status: active.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 3.1.6 |
| Published | 2026-07-27 |
| First published | 2026-05-21 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 106.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 303 |
| Author | kakajun |
| Maintainers | majun2232 |
| Keywords | sketch-ruler, ruler, canvas, renderer, input, framework-agnostic |

## Links

- npm: https://www.npmjs.com/package/@sketch-ruler/canvas
- Repository: https://github.com/kakajun/vue3-sketch-ruler
- Homepage: https://github.com/kakajun/vue3-sketch-ruler#readme
- Issues: https://github.com/kakajun/vue3-sketch-ruler/issues
- npm.io page: https://npm.io/package/@sketch-ruler/canvas

## Dependencies (1)

- [@sketch-ruler/core](https://npm.io/package/@sketch-ruler/core.md) 3.1.6

## Alternatives

- [exif-parser](https://npm.io/package/exif-parser.md) — 3.8M weekly downloads
- [vite-plugin-compression](https://npm.io/package/vite-plugin-compression.md) — 569.5K weekly downloads
- [pica](https://npm.io/package/pica.md) — 442.4K weekly downloads
- [@reportportal/client-javascript](https://npm.io/package/@reportportal/client-javascript.md) — 408.8K weekly downloads
- [@tldraw/state](https://npm.io/package/@tldraw/state.md) — 316.0K weekly downloads

## Recent versions

- 3.1.6 (latest) — 2026-07-27
- 3.1.5 — 2026-06-26
- 3.1.4 — 2026-05-29
- 3.1.3 — 2026-05-29
- 3.1.2 — 2026-05-28
- 3.1.1 — 2026-05-28
- 3.1.0 — 2026-05-26
- 3.0.2 — 2026-05-23
- 3.0.1 — 2026-05-23
- 3.0.0 — 2026-05-21
- 3.0.0-beta.0 — 2026-05-21

## README

# @sketch-ruler/canvas

> 框架无关的 Canvas 2D 渲染器与 DOM 输入管理器。负责标尺绘制、离屏缓存、鼠标/键盘/滚轮事件适配。依赖 `@sketch-ruler/core`。

## 安装

```bash
npm install @sketch-ruler/canvas
# 或
pnpm add @sketch-ruler/canvas
```

## 快速上手

### InputManager — 统一输入管理

绑定到画布容器，自动处理 **Ctrl+滚轮缩放**、**空格+拖拽平移**、**键盘快捷键**（Ctrl+0 / Ctrl++/Ctrl+-）。

```ts
import { InputManager } from '@sketch-ruler/canvas'
import { TransformEngine } from '@sketch-ruler/core'

const engine = new TransformEngine({ x: 0, y: 0, scale: 1 })

const inputManager = new InputManager(engine, {
  zoomStep: 0.25, // 滚轮缩放步长
  zoomMode: 'pointer', // 'pointer' | 'viewport-center' | 'content-center'
  viewportSize: { width: 1470, height: 700 },
  contentSize: { width: 1920, height: 1080 },
  onCursorChange: (cls) => {
    // cls: 'default' | 'grab' | 'grabbing'
    container.className = cls
  }
})

// 绑定到画布 DOM（事件实际绑定到 parentElement）
inputManager.bind(canvasElement)

// 动态切换缩放模式
inputManager.setZoomMode('viewport-center')

// 获取当前光标类名
const cursorClass = inputManager.getCursorClass()

// 清理
inputManager.destroy()
```

**事件处理细节：**

- **滚轮缩放**：按住 `Ctrl` / `Cmd` + 滚轮，以 `zoomMode` 指定的原点进行缩放
- **空格拖拽**：按住 `Space` + 鼠标左键拖拽平移
- **键盘快捷键**：
  - `Ctrl+0`：缩放到 100%
  - `Ctrl++` / `Ctrl+=`：放大
  - `Ctrl+-`：缩小
  - `Ctrl+1`：适配视口（留 5% 边距）

### Canvas2DRenderer — Canvas 2D 标尺渲染器

```ts
import { Canvas2DRenderer } from '@sketch-ruler/canvas'

const canvas = document.getElementById('ruler') as HTMLCanvasElement
const renderer = new Canvas2DRenderer(canvas)

renderer.render({
  width: 1400,
  height: 20,
  scale: 1,
  offset: 0,
  vertical: false, // false=水平标尺, true=垂直标尺
  thick: 20,
  marks: scaleMarks, // 由 core 的 computeScaleMarks 生成
  config: tickConfig,
  palette: {
    bgColor: '#f6f7f9',
    tickColor: '#BABBBC',
    labelColor: '#7D8694',
    borderColor: '#eeeeef'
  }
})
```

### 离屏缓存 — OffscreenRulerCache

用于频繁重绘场景，将标尺静态外观预渲染到离屏 Canvas，仅在配色/厚度/密度变更时重建。

```ts
import { OffscreenRulerCache } from '@sketch-ruler/canvas'

const cache = new OffscreenRulerCache()

// 在渲染循环中使用
const usedCache = cache.drawStatic(targetCtx, marks, {
  width: 1400,
  height: 20,
  ratio: window.devicePixelRatio,
  palette,
  thick: 20,
  vertical: false,
  canvasSize: 1000
})

// 清空缓存（如配色变更时）
cache.clear()
```

### 标签缓存 — LabelCache

缓存刻度文字标签，避免每帧重复测量文本和 fillText。

```ts
import { LabelCache } from '@sketch-ruler/canvas'

const labelCache = new LabelCache(500) // 最大缓存 500 条

// 在 Canvas2DRenderer 渲染循环中使用
const entry = labelCache.get(ctx, { text: '100', font: '12px Arial', color: '#7D8694' })
// entry: { canvas: HTMLCanvasElement, width: number, height: number }
ctx.drawImage(entry.canvas, x, y)

// 清空缓存
labelCache.clear()
```

### 滚轮标准化 — WheelNormalizer

将不同浏览器/操作系统的滚轮事件统一为标准格式。

```ts
import { normalizeWheel, getZoomDelta } from '@sketch-ruler/canvas'

canvas.addEventListener('wheel', (e) => {
  // 标准化滚轮事件
  const normalized = normalizeWheel(e)
  // normalized: { deltaX, deltaY, deltaZ, deltaMode }

  // 计算缩放增量（默认灵敏度 0.001）
  const delta = getZoomDelta(e, 0.001)
  engine.zoomBy(delta, e.clientX, e.clientY)
})
```

### 底层适配器（自行组合事件）

如果你不想用 `InputManager`，可以直接使用底层适配器：

```ts
import { MouseAdapter } from '@sketch-ruler/canvas'
import type { MouseAdapterCallbacks } from '@sketch-ruler/canvas'

const adapter = new MouseAdapter(parentElement, {
  onWheel: (e, normalized) => {
    // 自定义滚轮处理
  },
  onMouseDown: (e) => {
    // 自定义鼠标按下
  },
  onMouseMove: (e) => {
    // 自定义鼠标移动
  },
  onMouseUp: (e) => {
    // 自定义鼠标抬起
  },
  onMouseEnter: () => {},
  onMouseLeave: () => {}
} as MouseAdapterCallbacks)

adapter.bind()
// adapter.unbind()
```

```ts
import { KeyboardAdapter } from '@sketch-ruler/canvas'
import type { KeyCombo } from '@sketch-ruler/canvas'

const kb = new KeyboardAdapter({
  onShortcut: (combo: KeyCombo, e: KeyboardEvent) => {
    // combo: 'ctrl+0' | 'ctrl+plus' | 'ctrl+minus' | 'space' | ...
    console.log('shortcut', combo)
  }
})

kb.bind()
// kb.unbind()
```

## API 概览

| 导出                  | 类型 | 说明                                              |
| --------------------- | ---- | ------------------------------------------------- |
| `InputManager`        | 类   | 统一输入管理（滚轮/拖拽/键盘）                    |
| `MouseAdapter`        | 类   | 鼠标事件封装（wheel/mousedown/mousemove/mouseup） |
| `KeyboardAdapter`     | 类   | 键盘快捷键封装                                    |
| `normalizeWheel`      | 函数 | 滚轮事件标准化                                    |
| `getZoomDelta`        | 函数 | 从原生 WheelEvent 计算缩放增量                    |
| `Canvas2DRenderer`    | 类   | Canvas 2D 标尺渲染器                              |
| `OffscreenRulerCache` | 类   | 离屏标尺缓存                                      |
| `LabelCache`          | 类   | 刻度标签缓存                                      |

## 与 @sketch-ruler/core 的配合

```ts
import { TransformEngine, computeScaleMarks, getTickConfig } from '@sketch-ruler/core'
import { InputManager, Canvas2DRenderer } from '@sketch-ruler/canvas'

// 1. 创建引擎
const engine = new TransformEngine({ x: 0, y: 0, scale: 1 })

// 2. 绑定输入
const input = new InputManager(engine, { zoomMode: 'pointer' })
input.bind(canvasElement)

// 3. 监听状态并渲染
engine.onUpdate((state) => {
  // 更新 DOM transform
  content.style.transform = `matrix(${state.scale}, 0, 0, ${state.scale}, ${state.x}, ${state.y})`

  // 渲染标尺
  const marks = computeScaleMarks({
    scale: state.scale,
    offset: state.x,
    viewportSize: 1400,
    thick: 20,
    config: getTickConfig(state.scale)
  })
  renderer.render({ width: 1400, height: 20, scale: state.scale, offset: state.x, marks })
})
```

## License

MIT

---
_Source: https://npm.io/package/@sketch-ruler/canvas · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
