react-sketch-ruler
v3.1.4
Published
> 是一个基于 React + TypeScript 的标尺组件库,由 [vue3-sketch-ruler](https://github.com/kakajun/vue3-sketch-ruler) 翻译而来,共用 `@sketch-ruler/core` 与 `@sketch-ruler/canvas` 底层插件。适用于低代码平台、大屏可视化、做图工具等场景,提供类似 Photoshop 的缩放与标尺辅助线体验。
Maintainers
Readme
react-sketch-ruler
是一个基于 React + TypeScript 的标尺组件库,由 vue3-sketch-ruler 翻译而来,共用
@sketch-ruler/core与@sketch-ruler/canvas底层插件。适用于低代码平台、大屏可视化、做图工具等场景,提供类似 Photoshop 的缩放与标尺辅助线体验。
🚀 Features
- ⚛️ React 18+ / 19+ 友好,完全基于 TypeScript
- 🎯 内置 TransformEngine 变换引擎,零外部 panzoom 依赖
- 🖱️ 多种缩放模式:鼠标中心、视口中心、内容中心
- 📐 可配置参考线(拖拽创建、吸附、锁定)
- 🗺️ 内置 Minimap 缩略图导航(支持拖拽视口、点击跳转)
- 🔌 插件系统(生命周期钩子 + 自定义渲染器)
- 🎨 动画支持:
ease-out/damped/exponential/direct - 📦 平台与业务代码分离,通过
children与slot="toolbar"插槽专注业务即可
🦄 Demo
案例浏览: https://kakajun.github.io/react-sketch-ruler
安装
npm install --save react-sketch-ruler
# 或
yarn add react-sketch-ruler
# 或
pnpm add react-sketch-ruler引入方式
ESM
import { SketchRule, Minimap } from 'react-sketch-ruler'
import type { SketchRulerProps, SketchRulerMethods } from 'react-sketch-ruler'
import 'react-sketch-ruler/index.css'CDN
<script src="https://unpkg.com/react-sketch-ruler/lib/index.umd.js"></script>
<link rel="stylesheet" href="https://unpkg.com/react-sketch-ruler/lib/index.css" />
<script>
const { SketchRule, Minimap } = window.ReactSketchRuler
</script>使用
基础用法
import React, { useRef } from 'react'
import { SketchRule } from 'react-sketch-ruler'
import 'react-sketch-ruler/index.css'
const BasicDemo: React.FC = () => {
const sketchRef = useRef<SketchRulerMethods>(null)
const width = 1470
const height = 700
const canvasWidth = 1000
const canvasHeight = 500
const [scale, setScale] = React.useState(1)
const [lines, setLines] = React.useState({ h: [0, 250], v: [0, 500] })
return (
<div style={{ width, height }}>
<SketchRule
ref={sketchRef}
scale={scale}
width={width}
height={height}
canvasWidth={canvasWidth}
canvasHeight={canvasHeight}
thick={20}
lines={lines}
isShowReferLine={true}
enableAnimation={true}
animationMode="ease-out"
onZoomChange={(detail) => {
console.log('zoomchange', detail)
setScale(detail.scale)
}}
onUpdateLines={setLines}
>
<div data-type="page" style={{ width: canvasWidth, height: canvasHeight }}>
{/* 业务画布内容 */}
<img src="bg.png" style={{ width: '100%', height: '100%' }} alt="" />
</div>
<div slot="toolbar" className="btns">
<button onClick={() => sketchRef.current?.reset()}>还原</button>
<button onClick={() => sketchRef.current?.zoomIn()}>放大</button>
<button onClick={() => sketchRef.current?.zoomOut()}>缩小</button>
<button onClick={() => sketchRef.current?.zoomToPreset(1)}>100%</button>
<span>{(scale * 100).toFixed(0)}%</span>
</div>
</SketchRule>
</div>
)
}配合 Minimap
import React, { useRef, useState } from 'react'
import { SketchRule, Minimap } from 'react-sketch-ruler'
import type { SketchRulerMethods } from 'react-sketch-ruler'
const Demo: React.FC = () => {
const sketchRef = useRef<SketchRulerMethods>(null)
const [scale, setScale] = useState(1)
const [offset, setOffset] = useState({ x: 0, y: 0 })
const handleZoomChange = (detail: { scale: number; x: number; y: number }) => {
setScale(detail.scale)
setOffset({ x: detail.x, y: detail.y })
}
const handleNavigate = (x: number, y: number) => {
sketchRef.current?.setTransform({ x, y })
}
return (
<>
<SketchRule ref={sketchRef} scale={scale} onZoomChange={handleZoomChange} ...>
<div data-type="page">...</div>
</SketchRule>
<Minimap
contentWidth={1000}
contentHeight={700}
viewportX={offset.x}
viewportY={offset.y}
viewportWidth={1470}
viewportHeight={700}
scale={scale}
width={200}
height={150}
onNavigate={handleNavigate}
/>
</>
)
}插件系统
import { definePlugin } from 'react-sketch-ruler'
import type { SketchRulerPlugin } from 'react-sketch-ruler'
const myPlugin = definePlugin(() => ({
name: 'demo-logger',
beforeZoom(ctx) {
if (ctx.to > 3) ctx.cancel()
},
afterZoom(ctx) {
console.log('zoom', ctx.from, '→', ctx.to)
},
onLineCreate: (ctx) => console.log('line created', ctx.line.id),
onLineDelete: (ctx) => console.log('line deleted', ctx.line.id)
}))
// 使用(建议用 useMemo 缓存,避免反复注册)
function App() {
const plugins = React.useMemo(() => [myPlugin()], [])
return <SketchRule plugins={plugins} ... />
}插件支持以下生命周期钩子:beforeZoom / afterZoom / beforePan / afterPan / onSnap / onLineCreate / onLineDelete / onLineMove,以及自定义渲染器 registerRenderer。详见源码 packages/sketch-ruler/AGENTS.md。
Hooks
如果你需要更底层的控制能力,可以直接使用提供的 Hooks:
import {
useSketchRuler,
useCanvasTransform,
useGuideLines,
useInputManager,
useSnapDetection
} from 'react-sketch-ruler'API
Props
| 属性 | 描述 | 类型 | 默认值 |
| --- | --- | --- | --- |
| width | 容器宽度 | number | 1400 |
| height | 容器高度 | number | 800 |
| canvasWidth | 画布宽度 | number | 700 |
| canvasHeight | 画布高度 | number | 700 |
| thick | 标尺厚度 | number | 16 |
| scale | 缩放值(受控属性) | number | 1 |
| showRuler | 是否显示标尺 | boolean | true |
| isShowReferLine | 是否显示参考线 | boolean | true |
| lines | 初始化参考线 | { h: number[]; v: number[] } | { h: [], v: [] } |
| palette | 标尺样式配置 | PaletteType | {} |
| shadow | 阴影高亮区域 | { x, y, width, height } | { x:0, y:0, width:0, height:0 } |
| zoomMode | 缩放原点模式 | 'pointer' \| 'viewport-center' \| 'content-center' | 'pointer' |
| zoomStep | 缩放步长 | number | 0.25 |
| minZoom | 最小缩放 | number | 0.1 |
| maxZoom | 最大缩放 | number | 10 |
| enableAnimation | 是否启用动画 | boolean | false |
| animationMode | 动画模式 | 'direct' \| 'ease-out' \| 'damped' \| 'exponential' | 'ease-out' |
| autoCenter | 初始化自动居中 | boolean | true |
| paddingRatio | 自动居中边距比(0~0.5) | number | 0.2 |
| initialOffset | 初始偏移(autoCenter=false 时生效) | { x: number; y: number } | { x:0, y:0 } |
| snapThreshold | 吸附阈值 | number | 5 |
| lockLine | 是否锁定参考线 | boolean | false |
| selfHandle | 自行处理输入事件 | boolean | false |
| plugins | 插件列表 | SketchRulerPlugin[] | [] |
| showMinorTicks | 是否显示次刻度 | boolean | false |
| eyeIcon | 左上角睁眼图标 Base64 | string | — |
| closeEyeIcon | 左上角闭眼图标 Base64 | string | — |
| deleteLabel | 删除参考线提示文字 | string | '放开删除' |
| children | 画布内容与工具栏插槽 | React.ReactNode | — |
Callbacks
| 回调 | 描述 | 参数 |
| ------------------- | ------------------ | ---------------------------------------- |
| onUpdateScale | 缩放值变化 | (scale: number) => void |
| onZoomChange | 缩放/平移变化 | ({ scale, x, y }) => void |
| onUpdateLines | 参考线变化 | ({ h: number[], v: number[] }) => void |
| onUpdateLockLine | 参考线锁定状态变化 | (lock: boolean) => void |
| onHandleCornerClick | 左上角按钮点击 | (showReferLine: boolean) => void |
Ref
通过 ref 可以调用以下方法:
| 方法 | 描述 |
| ---------------------------------- | -------------------- |
| engine | TransformEngine 实例 |
| setTransform({ x?, y?, scale? }) | 设置变换状态 |
| zoomIn() | 放大 |
| zoomOut() | 缩小 |
| reset() | 重置到初始状态 |
| zoomToPreset(scale) | 缩放到预设比例 |
| setZoomMode(mode) | 设置缩放模式 |
Palette
| 属性 | 描述 | 默认值 |
| -------------------- | -------------- | ---------- |
| bgColor | 画布背景 | #f6f7f9 |
| tickColor | 刻度颜色 | #BABBBC |
| labelColor | 刻度标签颜色 | #7D8694 |
| guideLineColor | 参考线颜色 | #51d6a9 |
| guideLineLockedColor | 锁定参考线颜色 | #d4d7dc |
| hoverBg | 标签背景色 | transparent |
| hoverColor | 标签文字色 | #000 |
| borderColor | 尺子边框颜色 | #eeeeef |
| shadowColor | 阴影背景色 | #e9f7fe |
| fontShadowColor | 阴影字体颜色 | #106ebe |
| guideLineStyle | 参考线样式 | 'dashed' |
| guideLineWidth | 参考线宽度 | 1 |
| labelEnabled | 是否显示标签 | true |
Minimap API
| 属性 | 描述 | 类型 | 默认值 |
| -------------- | ----------- | -------- | ------ |
| contentWidth | 内容宽度 | number | — |
| contentHeight | 内容高度 | number | — |
| viewportX | 视口 X 偏移 | number | — |
| viewportY | 视口 Y 偏移 | number | — |
| viewportWidth | 视口宽度 | number | — |
| viewportHeight | 视口高度 | number | — |
| scale | 缩放比例 | number | — |
| width | 缩略图宽度 | number | 200 |
| height | 缩略图高度 | number | 150 |
| 回调 | 描述 | 参数 |
| ----------- | -------------- | -------------------------------- |
| onNavigate | 导航到指定位置 | (x: number, y: number) => void |
| onDragStart | 开始拖拽 | () => void |
| onDragEnd | 结束拖拽 | () => void |
2.x → 3.x 迁移指南
v3.x 是架构重构版本,与 vue3-sketch-ruler v3.x 对齐,内置 TransformEngine 替代了外部 simple-panzoom 依赖,并引入了 Minimap、插件系统、动画系统等全新能力。
主要 Breaking Changes
| 变更项 | 2.x 写法 | 3.x 写法 | 说明 |
| --- | --- | --- | --- |
| 组件名 | <SketchRule> | <SketchRule>(保持不变) | — |
| 导出方式 | import SketchRule from 'react-sketch-ruler' | import { SketchRule } from 'react-sketch-ruler' | 改为命名导出,仍保留默认导出兼容 |
| 工具栏插槽 | 通过 ref 调用 | slot="toolbar" 子元素 | 在 children 中传入 <div slot="toolbar">...</div> |
| 缩放事件 | onZoomChange / updateScale | onUpdateScale / onZoomChange | onUpdateScale 仅通知 scale;onZoomChange 返回 { scale, x, y } |
| 参考线事件 | handleLine | onUpdateLines | 统一回调命名风格 |
| 偏移控制 | panzoomOption | autoCenter、paddingRatio、initialOffset | 移除 panzoomOption,改为内置引擎直接配置 |
| 缩放控制 | panzoomOption | zoomMode、zoomStep、minZoom、maxZoom | 内置引擎直接配置 |
| 动画系统 | 无 | enableAnimation、animationMode | 新增,支持 ease-out、damped、exponential、direct |
| 阴影文字 | showShadowText | 移除 | 3.x 已移除该属性 |
| palette 属性 | lineType、lineColor、longfgColor、fontColor | guideLineStyle、guideLineColor、tickColor、labelColor | 命名规范化 |
| Ref 暴露 | panzoomInstance | engine(TransformEngine) | 直接暴露内置引擎实例 |
| Ref 方法 | zoomIn()、zoomOut()、reset() | 同上,并新增 setTransform()、zoomToPreset()、setZoomMode() | 方法更丰富 |
| 外部依赖 | simple-panzoom | 零外部 panzoom 依赖 | 需从项目中移除 simple-panzoom |
快速迁移示例
2.x 代码:
import SketchRule from 'react-sketch-ruler'
;<SketchRule
ref={sketchruleRef}
scale={state.scale}
panzoomOption={panzoomOption}
palette={{ lineType: 'dashed', lineColor: '#51d6a9' }}
handleLine={handleLinesChange}
>
<div>...</div>
</SketchRule>3.x 代码:
import { SketchRule } from 'react-sketch-ruler'
;<SketchRule
ref={sketchRef}
scale={state.scale}
zoomMode="pointer"
enableAnimation={true}
animationMode="ease-out"
palette={{ guideLineStyle: 'dashed', guideLineColor: '#51d6a9' }}
onUpdateLines={handleLinesChange}
onZoomChange={handleZoomChange}
>
<div>...</div>
<div slot="toolbar">
<button onClick={() => sketchRef.current?.reset()}>还原</button>
<button onClick={() => sketchRef.current?.zoomIn()}>放大</button>
<button onClick={() => sketchRef.current?.zoomOut()}>缩小</button>
<button onClick={() => sketchRef.current?.zoomToPreset(1)}>100%</button>
</div>
</SketchRule>新增能力速览
- Minimap 缩略图:独立组件,支持拖拽视口与点击跳转
- 插件系统:通过
plugins属性注入生命周期钩子 - 吸附引擎:
snapThreshold配置参考线吸附阈值 - 动画引擎:
enableAnimation+animationMode实现平滑缩放/平移 - 多实例支持:每个
SketchRule实例独立管理自己的 TransformEngine - 纯原生零依赖:核心引擎
@sketch-ruler/core纯原生实现,无需 panzoom 等第三方库
开发
# 安装依赖
pnpm install
# 开发模式(先构建组件库,再启动文档站点)
pnpm dev
# 构建组件库
pnpm build
# 构建文档站点
pnpm build:demo
# 运行测试
pnpm test
# 格式化与检查
pnpm fmt
pnpm lint:check🌈 应用案例
如果你正在使用
react-sketch-ruler,欢迎提交 PR 添加你的项目!
QQ 技术交流群
贡献者
最后
这是个开源业余做的功能,欢迎加强该插件的小伙伴加入。如果 react-sketch-ruler 对您有帮助,请给个 star,您的鼓励是我最大的动力。
引用
- Vue3 版本:vue3-sketch-ruler
- Vue2 版本:vue-sketch-ruler
