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

@sketch-ruler/canvas

v3.1.5

Published

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

Readme

@sketch-ruler/canvas

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

安装

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

快速上手

InputManager — 统一输入管理

绑定到画布容器,自动处理 Ctrl+滚轮缩放空格+拖拽平移键盘快捷键(Ctrl+0 / Ctrl++/Ctrl+-)。

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 标尺渲染器

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,仅在配色/厚度/密度变更时重建。

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。

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

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

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,可以直接使用底层适配器:

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()
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 的配合

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