feat(tool): shape
This commit is contained in:
77
components/label/components/AssistShapeComponent.tsx
Normal file
77
components/label/components/AssistShapeComponent.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
"use client"
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
} from "react"
|
||||
|
||||
interface AssistShapeComponentProps {
|
||||
size: number
|
||||
}
|
||||
|
||||
const AssistShapeComponent = (
|
||||
props: AssistShapeComponentProps,
|
||||
ref: React.Ref<unknown> | undefined
|
||||
) => {
|
||||
const { size } = props
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||
|
||||
const drawAssistShape = useCallback(
|
||||
(centerX: number, centerY: number) => {
|
||||
const canvas = canvasRef.current
|
||||
const ctx = canvas?.getContext("2d")
|
||||
if (!canvas || !ctx) return
|
||||
|
||||
const radius = Math.max(1, size)
|
||||
const side = radius * 2
|
||||
const left = centerX - radius
|
||||
const top = centerY - radius
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = "#EF4444"
|
||||
ctx.lineWidth = 2
|
||||
ctx.setLineDash([6, 4])
|
||||
ctx.strokeRect(left, top, side, side)
|
||||
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2)
|
||||
ctx.stroke()
|
||||
},
|
||||
[size]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current
|
||||
if (!canvas) return
|
||||
canvas.width = window.innerWidth
|
||||
canvas.height = window.innerHeight
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
drawAssistShape(rect.width / 2, rect.height / 2)
|
||||
}, [drawAssistShape])
|
||||
|
||||
const updateAssistShape = (event: { clientX: number; clientY: number }) => {
|
||||
const canvas = canvasRef.current
|
||||
if (!canvas) return
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
const centerX = event.clientX - rect.left
|
||||
const centerY = event.clientY - rect.top
|
||||
drawAssistShape(centerX, centerY)
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({ updateAssistShape }))
|
||||
|
||||
return (
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
style={{
|
||||
backgroundColor: "transparent",
|
||||
position: "absolute",
|
||||
zIndex: 52,
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default forwardRef(AssistShapeComponent)
|
||||
@@ -59,6 +59,7 @@ import { checkCommentsIsSame } from "../util"
|
||||
import { safeClone } from "../utils/clone"
|
||||
import { labelTypeMap } from "../utils/constants"
|
||||
import { adjustPoints } from "../utils/paperjs"
|
||||
import AssistShapeComponent from "./AssistShapeComponent"
|
||||
import CrosshairComponent from "./CrosshairComponent"
|
||||
import { renderOperationIcon } from "./RightObjectTools"
|
||||
|
||||
@@ -222,6 +223,8 @@ const PaperContainer = (
|
||||
objectOperations,
|
||||
imageFilter,
|
||||
crosshairStatus,
|
||||
assistToolEnabled,
|
||||
assistToolSize,
|
||||
showTags,
|
||||
showTagsConfigs,
|
||||
} = useTopToolsStore()
|
||||
@@ -2671,9 +2674,11 @@ const PaperContainer = (
|
||||
}, [activeImage])
|
||||
|
||||
const crosshairComponentRef = useRef<any>(null)
|
||||
const assistShapeComponentRef = useRef<any>(null)
|
||||
|
||||
const handleCrosshairMove = (event: { clientX: number; clientY: number }) => {
|
||||
crosshairComponentRef.current?.updateCrosshair(event)
|
||||
assistShapeComponentRef.current?.updateAssistShape(event)
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
@@ -2703,6 +2708,12 @@ const PaperContainer = (
|
||||
ref={crosshairComponentRef}
|
||||
/>
|
||||
)}
|
||||
{assistToolEnabled && (
|
||||
<AssistShapeComponent
|
||||
size={assistToolSize}
|
||||
ref={assistShapeComponentRef}
|
||||
/>
|
||||
)}
|
||||
{imgSize?.clientWidth && imgSize?.clientHeight && (
|
||||
<canvas
|
||||
id="paper-canvas"
|
||||
|
||||
@@ -214,6 +214,10 @@ const TopTools = (
|
||||
setImageFilter,
|
||||
crosshairStatus,
|
||||
setCrosshairStatus,
|
||||
assistToolEnabled,
|
||||
setAssistToolEnabled,
|
||||
assistToolSize,
|
||||
setAssistToolSize,
|
||||
needBackup,
|
||||
setNeedBackup,
|
||||
checkSize,
|
||||
@@ -2030,6 +2034,36 @@ const TopTools = (
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
<Flex justify="space-between" align="center" p={8} gap={4}>
|
||||
<ActionIcon
|
||||
variant="transparent"
|
||||
style={{ cursor: "pointer" }}
|
||||
c={assistToolEnabled ? "blue" : "var(--mantine-color-text)"}
|
||||
onClick={() => {
|
||||
setAssistToolEnabled(!assistToolEnabled)
|
||||
}}>
|
||||
<Eclipse size={16} />
|
||||
</ActionIcon>
|
||||
<NumberInput
|
||||
value={assistToolSize}
|
||||
w={58}
|
||||
min={1}
|
||||
size="xs"
|
||||
hideControls
|
||||
onChange={(v) => {
|
||||
const next = Number(v)
|
||||
if (Number.isFinite(next) && next >= 1) {
|
||||
setAssistToolSize(next)
|
||||
}
|
||||
}}
|
||||
onFocus={() => {
|
||||
useKeyEventStore.getState().setFocusInput(true)
|
||||
}}
|
||||
onBlur={() => {
|
||||
useKeyEventStore.getState().setFocusInput(false)
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
<Divider orientation="vertical" />
|
||||
<Flex justify="center" align="center">
|
||||
<ActionIcon
|
||||
|
||||
@@ -28,6 +28,10 @@ interface TopToolsState {
|
||||
) => void
|
||||
crosshairStatus: "hidden" | "line" | "carve"
|
||||
setCrosshairStatus: (val: "hidden" | "line" | "carve") => void
|
||||
assistToolEnabled: boolean
|
||||
setAssistToolEnabled: (val: boolean) => void
|
||||
assistToolSize: number
|
||||
setAssistToolSize: (val: number) => void
|
||||
showTags: boolean
|
||||
setShowTags: (val: boolean) => void
|
||||
showTagsConfigs: string[]
|
||||
@@ -85,6 +89,8 @@ const initialTopToolsState = {
|
||||
brightness: 0,
|
||||
},
|
||||
crosshairStatus: "hidden" as "hidden" | "line" | "carve",
|
||||
assistToolEnabled: false,
|
||||
assistToolSize: 10,
|
||||
drawOption: "default" as "default" | "intersect" | "unite",
|
||||
saveCurrentScale: false,
|
||||
scale: 1,
|
||||
@@ -156,6 +162,18 @@ export const useTopToolsStore = create<TopToolsState>()(
|
||||
...state,
|
||||
crosshairStatus: val,
|
||||
})),
|
||||
assistToolEnabled: initialTopToolsState.assistToolEnabled,
|
||||
setAssistToolEnabled: (val) =>
|
||||
set((state: TopToolsState) => ({
|
||||
...state,
|
||||
assistToolEnabled: val,
|
||||
})),
|
||||
assistToolSize: initialTopToolsState.assistToolSize,
|
||||
setAssistToolSize: (val) =>
|
||||
set((state: TopToolsState) => ({
|
||||
...state,
|
||||
assistToolSize: Math.max(1, val),
|
||||
})),
|
||||
showTags: false,
|
||||
setShowTags: (val) =>
|
||||
set((state: TopToolsState) => ({
|
||||
|
||||
Reference in New Issue
Block a user