@scena/react-ruler 是一款轻量、可定制的 React 标尺组件,支持水平 / 垂直方向、缩放、滚动偏移适配,非常适合可视化编辑器、画布标注等场景。

安装
官网地址: https://daybrush.com/ruler/
javascript
npm install @scena/react-ruler --save
核心api
| 属性 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| type | horizontal/vertical | 标尺方向(水平 / 垂直) | horizontal |
| width | number | 标尺宽度(水平标尺生效) | 100% |
| height | number | 标尺高度(垂直标尺生效) | 100% |
| zoom | number | 标尺缩放比例(与画布缩放联动) | 1 |
| scrollPos | number | 标尺滚动偏移(与画布滚动联动) | 0 |
| unit | number 标尺刻度单位 | (如 50 = 每 50px 一个大刻度) | 50 |
| segment | number | 大刻度下的小分段数(如 2=50px 分 2 段) | 2 |
| lineColor | string | 刻度线颜色 | #ddd |
| textColor | string | 刻度文字颜色 | #888 |
| backgroundColor | string | 标尺背景色 | #fff |
| negativeRuler | boolean | 是否显示负数刻度(支持画布左 / 上偏移) | false |
| textOffset | [number, number] | 刻度文字的偏移量,格式为 [x, y],单位:px;方向适配水平 / 垂直标尺 | [0, 0] |
实现案例
javascript
import { useEffect, useRef, useMemo, useCallback } from "react";
import { useEditScreen } from '@/store/useEditScreen'
import Ruler from "@scena/react-ruler";
import './index.scss'
const RulerComponent = (props) => {
const { children } = props
const verticalRulerRef = useRef<null | Ruler>(null)
const horizontalRulerRef = useRef<null | Ruler>(null
return (
<div className="ruler-container">
<div className="left">
<div className="px-box">px</div>
{/* 垂直ruler */}
<Ruler
ref={verticalRulerRef}
type="vertical"
lineColor={"#aaa"}
textColor={"#000"}
backgroundColor={"#fff"}
negativeRuler={true}
segment={2}
textOffset={[10, 0]}
/>
</div>
<div className="right">
<div style={{ height: "20px" }}>
{/* 水平ruler */}
<Ruler
type="horizontal"
ref={horizontalRulerRef}
lineColor={"#aaa"}
textColor={"#000"}
backgroundColor={"#fff"}
negativeRuler={true}
segment={2}
textOffset={[0, 10]}
/>
</div>
{ children }
</div>
</div>
);
}
export default RulerComponent
样式
javascript
.ruler-container {
width: 100%;
height: calc(100% - 40px);
display: flex;
overflow: hidden;
.left {
width: 20px;
height: 100%;
}
.px-box {
font-size: 12px;
text-align: center;
height: 20px;
background: #fff;
}
.right {
flex: 1;
}
}
核心联动逻辑
1. 缩放联动
- 标尺的zoom必须与画布的transForm: scale(scale)同步
- 刻度单位 unit 需根据缩放比例动态调整(缩放越大,单位越小,保证刻度不重叠)
- 画布缩放原点必须设为 transform-origin: left top,与标尺原点对齐
2. 画布缩放原点必须设为 transform-origin: left top,与标尺原点对齐
- 容器滚动时,scrollPosX = scrollLeft / scale、scrollPosY = scrollTop / scale(滚动偏移需转换为逻辑像素);
- 开启 negativeRuler={true} 支持负数刻度,适配画布左 / 上偏移场景
- 标尺 scrollPos 是「逻辑像素偏移」,需除以缩放比例才能与画布滚动偏移匹配
3. 坐标对齐
- 画布内元素的绝对定位(left/top)是「逻辑像素」,与标尺刻度一一对应
- 若需将标尺刻度转换为屏幕物理像素,需乘以缩放比例(逻辑像素 × scale = 物理像素)
其它配置
自定义刻度文字格式
通过 formatText 属性自定义刻度显示(如添加单位、格式化数字):
javascript
<Ruler
type="horizontal"
zoom={scale}
scrollPos={scrollPosX}
formatText={(value) => `${value}px`} // 刻度显示为 "50px" "100px"
/>
隐藏小刻度 / 文字
通过 showMinorLine/showText 控制显示
javascript
<Ruler
type="vertical"
showMinorLine={scale > 0.5} // 缩放小于0.5时隐藏小刻度
showText={scale > 0.3} // 缩放小于0.3时隐藏文字
/>
标尺偏移校准
若标尺刻度与画布坐标错位,可通过 offset 属性微调:
javascript
<Ruler
type="horizontal"
offset={2} // 水平偏移2px
/>
五、常见问题与解决方案
1. 标尺刻度与画布坐标错位
- 检查画布 transform-origin 是否为 left top;
- 确保 scrollPos 计算时除以了缩放比例(scrollLeft / scale);
- 校准标尺 offset 属性,微调像素偏差。
2. 缩放后刻度重叠
- 动态调整 unit 属性(缩放越大,unit 越小);
- 缩放过小时隐藏小刻度 / 文字(showMinorLine/showText)。
3. 滚轮缩放卡顿
- 给 handleWheel 添加 e.preventDefault() 阻止默认滚动;
- 限制缩放范围(如 0.2~2),避免极端缩放;
- 使用 requestAnimationFrame 优化缩放计算(高频操作)。
4. 负数刻度不显示
- 确保开启 negativeRuler={true};
- 检查 scrollPos 是否为负数(画布左 / 上滚动时才会显示负数刻度)。
在计算屏幕缩放的比例的时候 使用了antDesign Layout布局 导致获取元素clientHiehgt一直有问题 后面把Layout布局改成了div