fix(tool): scale

This commit is contained in:
zhangheng
2026-04-21 20:47:15 +08:00
parent 8776ce4181
commit 7478788efd
2 changed files with 32 additions and 39 deletions

View File

@@ -329,10 +329,6 @@ const LabelPage = ({
const activeRasterScale = usePaperStore( const activeRasterScale = usePaperStore(
(state) => state.rasterScale[activeImage] ?? 1 (state) => state.rasterScale[activeImage] ?? 1
) )
const activeRasterSize = usePaperStore(
(state) => state.rasterSize[activeImage] ?? null
)
const currentGroup = usePaperStore((state) => state.group)
const { const {
setDescOperations, setDescOperations,
metaOperation, metaOperation,
@@ -347,22 +343,6 @@ const LabelPage = ({
viewScale: scale, viewScale: scale,
}) })
}, [activeRasterScale, scale]) }, [activeRasterScale, scale])
const scaleOffsets = useMemo(() => {
if (!currentGroup || !activeRasterSize?.[0] || !activeRasterSize?.[1]) {
return {
offsetX: 0,
offsetY: 0,
}
}
const displayedWidth = activeRasterSize[0] * displayedImageScale
const displayedHeight = activeRasterSize[1] * displayedImageScale
return {
offsetX: displayedWidth / 2 - currentGroup.position.x,
offsetY: displayedHeight / 2 - currentGroup.position.y,
}
}, [activeRasterSize, currentGroup, displayedImageScale])
const asyncGetProjectDetail = useCallback(async () => { const asyncGetProjectDetail = useCallback(async () => {
if (projectId) { if (projectId) {
@@ -2727,8 +2707,6 @@ const LabelPage = ({
style={{ overflow: "hidden" }}> style={{ overflow: "hidden" }}>
<ScaleComponent <ScaleComponent
options={{ options={{
offsetX: scaleOffsets.offsetX,
offsetY: scaleOffsets.offsetY,
scale: displayedImageScale, scale: displayedImageScale,
}} }}
mode="horizontal" mode="horizontal"
@@ -2736,8 +2714,6 @@ const LabelPage = ({
<Flex h="calc(100% - 32px)"> <Flex h="calc(100% - 32px)">
<ScaleComponent <ScaleComponent
options={{ options={{
offsetX: scaleOffsets.offsetX,
offsetY: scaleOffsets.offsetY,
scale: displayedImageScale, scale: displayedImageScale,
}} }}
mode="vertical" mode="vertical"

View File

@@ -4,8 +4,6 @@ import React, { useCallback, useEffect, useRef } from "react"
interface ScaleComponentProps { interface ScaleComponentProps {
options: { options: {
offsetX: number
offsetY: number
scale: number scale: number
} }
mode: "horizontal" | "vertical" mode: "horizontal" | "vertical"
@@ -14,6 +12,7 @@ interface ScaleComponentProps {
const ScaleComponent: React.FC<ScaleComponentProps> = (props) => { const ScaleComponent: React.FC<ScaleComponentProps> = (props) => {
const { options, mode } = props const { options, mode } = props
const canvasRef = useRef<HTMLCanvasElement>(null) const canvasRef = useRef<HTMLCanvasElement>(null)
const FLOAT_EPSILON = 0.0000001
const getFixed = (sparsity: number) => { const getFixed = (sparsity: number) => {
const pointIdx = String(sparsity).indexOf(".") const pointIdx = String(sparsity).indexOf(".")
@@ -22,8 +21,13 @@ const ScaleComponent: React.FC<ScaleComponentProps> = (props) => {
} }
const isCloseToInteger = (num: number) => { const isCloseToInteger = (num: number) => {
return Math.abs(num - Math.round(num)) < 0.0000001 return Math.abs(num - Math.round(num)) < FLOAT_EPSILON
} }
const normalizeScaleValue = (num: number) => {
return Math.abs(num) < FLOAT_EPSILON ? 0 : num
}
const getSparsity = (scale: number) => { const getSparsity = (scale: number) => {
if (scale <= 1) { if (scale <= 1) {
return Math.round(100 / scale) return Math.round(100 / scale)
@@ -63,20 +67,30 @@ const ScaleComponent: React.FC<ScaleComponentProps> = (props) => {
ctx.font = "12px serif" ctx.font = "12px serif"
ctx.beginPath() ctx.beginPath()
const { offsetX, offsetY, scale } = options const { scale } = options
const offset = mode === "horizontal" ? offsetX : offsetY if (!Number.isFinite(scale) || scale <= 0) {
ctx.restore()
return
}
// 间隔 // 间隔
const sparsity = getSparsity(scale) const sparsity = getSparsity(scale)
// 间隔内有多少条线 // 间隔内有多少条线
const part = 10 const part = 10
const pixelPerUnit = scale * sparsity const pixelPerUnit = scale * sparsity
const gap = pixelPerUnit / part const gap = pixelPerUnit / part
const unitGap = sparsity / part
const fixed = getFixed(sparsity) const fixed = getFixed(sparsity)
let index = offset % gap > 0 ? gap - (offset % gap) : -offset % gap
if (mode === "horizontal") { if (mode === "horizontal") {
ctx.translate(31.5, 0) ctx.translate(31.5, 0)
do { const maxWidth = Math.max(0, w - 32)
const num = ((offset + index) / pixelPerUnit) * sparsity for (
let tickIndex = 0;
tickIndex * gap <= maxWidth + FLOAT_EPSILON;
tickIndex += 1
) {
const index = tickIndex * gap
const num = normalizeScaleValue(tickIndex * unitGap)
if (isCloseToInteger(num / sparsity)) { if (isCloseToInteger(num / sparsity)) {
ctx.moveTo(index, h * 0.5) ctx.moveTo(index, h * 0.5)
ctx.lineTo(index, h) ctx.lineTo(index, h)
@@ -87,12 +101,16 @@ const ScaleComponent: React.FC<ScaleComponentProps> = (props) => {
ctx.moveTo(index, h * 0.7) ctx.moveTo(index, h * 0.7)
ctx.lineTo(index, h) ctx.lineTo(index, h)
} }
index += gap }
} while (index < w)
} else { } else {
ctx.translate(0, 0.5) ctx.translate(0, 0.5)
do { for (
const num = ((offset + index) / pixelPerUnit) * sparsity let tickIndex = 0;
tickIndex * gap <= h + FLOAT_EPSILON;
tickIndex += 1
) {
const index = tickIndex * gap
const num = normalizeScaleValue(tickIndex * unitGap)
if (isCloseToInteger(num / sparsity)) { if (isCloseToInteger(num / sparsity)) {
ctx.moveTo(w * 0.5, index) ctx.moveTo(w * 0.5, index)
ctx.lineTo(w, index) ctx.lineTo(w, index)
@@ -110,8 +128,7 @@ const ScaleComponent: React.FC<ScaleComponentProps> = (props) => {
ctx.moveTo(w * 0.7, index) ctx.moveTo(w * 0.7, index)
ctx.lineTo(w, index) ctx.lineTo(w, index)
} }
index += gap }
} while (index < h)
} }
ctx.closePath() ctx.closePath()
ctx.stroke() ctx.stroke()
@@ -129,7 +146,7 @@ const ScaleComponent: React.FC<ScaleComponentProps> = (props) => {
if (mode === "horizontal") { if (mode === "horizontal") {
return { return {
...baseStyles, ...baseStyles,
width: "100vw", width: "100%",
height: "32px", height: "32px",
cursor: "col-resize", cursor: "col-resize",
} }