feat(circle): change size
This commit is contained in:
@@ -1022,16 +1022,12 @@ const PaperContainer = (
|
|||||||
parent: usePaperStore.getState().group,
|
parent: usePaperStore.getState().group,
|
||||||
strokeScaling: false,
|
strokeScaling: false,
|
||||||
})
|
})
|
||||||
if (Math.abs(path.area) < useTopToolsStore.getState().checkSize) {
|
if (hollows[index]) {
|
||||||
path.remove()
|
path.data.isHollowPolygon = true
|
||||||
|
innerPaths.push(path)
|
||||||
} else {
|
} else {
|
||||||
if (hollows[index]) {
|
path.fillColor = new paper.Color(fillColor)
|
||||||
path.data.isHollowPolygon = true
|
outerPaths.push(path)
|
||||||
innerPaths.push(path)
|
|
||||||
} else {
|
|
||||||
path.fillColor = new paper.Color(fillColor)
|
|
||||||
outerPaths.push(path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -92,7 +92,12 @@ import { useKeyboardStore } from "../useKeyBoardStore"
|
|||||||
import { usePaperStore } from "../usePaperStore"
|
import { usePaperStore } from "../usePaperStore"
|
||||||
import { useRightToolsStore } from "../useRightToolsStore"
|
import { useRightToolsStore } from "../useRightToolsStore"
|
||||||
import { useIntervalStore, useLabelTimeStore } from "../useTimerStore"
|
import { useIntervalStore, useLabelTimeStore } from "../useTimerStore"
|
||||||
import { useTopToolsStore } from "../useTopToolsStore"
|
import {
|
||||||
|
DEFAULT_NODE_SIZE,
|
||||||
|
NODE_SIZE_MAX,
|
||||||
|
NODE_SIZE_MIN,
|
||||||
|
useTopToolsStore,
|
||||||
|
} from "../useTopToolsStore"
|
||||||
import { getSubAttrStatus } from "../util"
|
import { getSubAttrStatus } from "../util"
|
||||||
import { safeClone } from "../utils/clone"
|
import { safeClone } from "../utils/clone"
|
||||||
import { labelTypeMap, TaskStatusEnum } from "../utils/constants"
|
import { labelTypeMap, TaskStatusEnum } from "../utils/constants"
|
||||||
@@ -222,13 +227,14 @@ const TopTools = (
|
|||||||
setAssistToolEnabled,
|
setAssistToolEnabled,
|
||||||
assistToolSize,
|
assistToolSize,
|
||||||
setAssistToolSize,
|
setAssistToolSize,
|
||||||
|
nodeSize,
|
||||||
|
setNodeSize,
|
||||||
needBackup,
|
needBackup,
|
||||||
setNeedBackup,
|
setNeedBackup,
|
||||||
checkSize,
|
|
||||||
setCheckSize,
|
|
||||||
magnetFlag,
|
magnetFlag,
|
||||||
setMagnetFlag,
|
setMagnetFlag,
|
||||||
} = useTopToolsStore()
|
} = useTopToolsStore()
|
||||||
|
const [nodeSizeInput, setNodeSizeInput] = useState<number | string>(nodeSize)
|
||||||
|
|
||||||
const { pathGroupMap } = useRightToolsStore()
|
const { pathGroupMap } = useRightToolsStore()
|
||||||
const isAutoSave = useIntervalStore((state) => state.isAutoSave)
|
const isAutoSave = useIntervalStore((state) => state.isAutoSave)
|
||||||
@@ -247,6 +253,11 @@ const TopTools = (
|
|||||||
].filter(Boolean).length
|
].filter(Boolean).length
|
||||||
}, [projectDetail, showDescList, showGroupList, showObjectList, showTaskList])
|
}, [projectDetail, showDescList, showGroupList, showObjectList, showTaskList])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setNodeSizeInput(nodeSize)
|
||||||
|
usePaperStore.getState().refreshNodeVisualSize()
|
||||||
|
}, [nodeSize])
|
||||||
|
|
||||||
const toggleRightPanel = useCallback(
|
const toggleRightPanel = useCallback(
|
||||||
(visible: boolean, setter: (val: boolean) => void) => {
|
(visible: boolean, setter: (val: boolean) => void) => {
|
||||||
const nextVisible = !visible
|
const nextVisible = !visible
|
||||||
@@ -2188,23 +2199,39 @@ const TopTools = (
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justify="space-between" align="center" px="xs" gap="xs">
|
<Flex justify="space-between" align="center" px="xs" gap="xs">
|
||||||
<NumberInput
|
<Tooltip label={`节点直径范围 ${NODE_SIZE_MIN}-${NODE_SIZE_MAX}`}>
|
||||||
value={checkSize}
|
<Flex align="center" gap={4}>
|
||||||
w={50}
|
<Text span size="xs" style={{ minWidth: "fit-content" }}>
|
||||||
min={1}
|
节点
|
||||||
size="xs"
|
</Text>
|
||||||
radius="sm"
|
<NumberInput
|
||||||
hideControls
|
value={nodeSizeInput}
|
||||||
onChange={(v) => {
|
w={50}
|
||||||
if (v) setCheckSize(Number(v))
|
min={NODE_SIZE_MIN}
|
||||||
}}
|
max={NODE_SIZE_MAX}
|
||||||
onFocus={() => {
|
step={1}
|
||||||
useKeyEventStore.getState().setFocusInput(true)
|
allowDecimal={false}
|
||||||
}}
|
size="xs"
|
||||||
onBlur={() => {
|
radius="sm"
|
||||||
useKeyEventStore.getState().setFocusInput(false)
|
hideControls
|
||||||
}}
|
onChange={(value) => {
|
||||||
/>
|
setNodeSizeInput(value)
|
||||||
|
}}
|
||||||
|
onFocus={() => {
|
||||||
|
useKeyEventStore.getState().setFocusInput(true)
|
||||||
|
}}
|
||||||
|
onBlur={(event) => {
|
||||||
|
useKeyEventStore.getState().setFocusInput(false)
|
||||||
|
const rawValue = event.currentTarget.value.trim()
|
||||||
|
const nextValue =
|
||||||
|
rawValue === "" ? DEFAULT_NODE_SIZE : Number(rawValue)
|
||||||
|
setNodeSize(
|
||||||
|
Number.isFinite(nextValue) ? nextValue : DEFAULT_NODE_SIZE
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Tooltip>
|
||||||
{renderEditIcon}
|
{renderEditIcon}
|
||||||
<Button
|
<Button
|
||||||
w="fit-content"
|
w="fit-content"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { useKeyboardStore } from "./useKeyBoardStore"
|
|||||||
import { useOtherToolsStore } from "./useOtherToolsStore"
|
import { useOtherToolsStore } from "./useOtherToolsStore"
|
||||||
import { usePaperSupportStore } from "./usePaperSupportStore"
|
import { usePaperSupportStore } from "./usePaperSupportStore"
|
||||||
import { useRightToolsStore } from "./useRightToolsStore"
|
import { useRightToolsStore } from "./useRightToolsStore"
|
||||||
import { useTopToolsStore } from "./useTopToolsStore"
|
import { DEFAULT_NODE_SIZE, useTopToolsStore } from "./useTopToolsStore"
|
||||||
import { safeClone } from "./utils/clone"
|
import { safeClone } from "./utils/clone"
|
||||||
|
|
||||||
interface ContinuePolygonTarget {
|
interface ContinuePolygonTarget {
|
||||||
@@ -183,6 +183,7 @@ interface PaperState {
|
|||||||
setContinuePolygonTarget: (target: ContinuePolygonTarget | null) => void
|
setContinuePolygonTarget: (target: ContinuePolygonTarget | null) => void
|
||||||
beginContinuePolygonDraft: () => boolean
|
beginContinuePolygonDraft: () => boolean
|
||||||
setLoadingData: (flag: boolean) => void
|
setLoadingData: (flag: boolean) => void
|
||||||
|
refreshNodeVisualSize: () => void
|
||||||
resizeGhostRequestToken: number
|
resizeGhostRequestToken: number
|
||||||
requestResizeGhost: () => void
|
requestResizeGhost: () => void
|
||||||
}
|
}
|
||||||
@@ -328,6 +329,7 @@ const PAPER_CONTEXT_HIT_TYPES = [
|
|||||||
"pathBuff",
|
"pathBuff",
|
||||||
"pathCircle",
|
"pathCircle",
|
||||||
] as const
|
] as const
|
||||||
|
const LEGACY_PAPER_NODE_DIAMETER = 6
|
||||||
|
|
||||||
const isPaperObjectType = (type: unknown) =>
|
const isPaperObjectType = (type: unknown) =>
|
||||||
typeof type === "string" &&
|
typeof type === "string" &&
|
||||||
@@ -339,6 +341,39 @@ const isPaperContextHitType = (type: unknown) =>
|
|||||||
type as (typeof PAPER_CONTEXT_HIT_TYPES)[number]
|
type as (typeof PAPER_CONTEXT_HIT_TYPES)[number]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const getPaperNodeDiameter = () => {
|
||||||
|
const configuredDiameter = useTopToolsStore.getState().nodeSize
|
||||||
|
return Number.isFinite(configuredDiameter)
|
||||||
|
? Math.round(configuredDiameter)
|
||||||
|
: DEFAULT_NODE_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPaperNodeRadius = () => getPaperNodeDiameter() / 2
|
||||||
|
|
||||||
|
const getPaperNodeScaleFactor = () => {
|
||||||
|
const currentScaling = usePaperStore.getState().group?.scaling.x || 1
|
||||||
|
const newScale = useTopToolsStore.getState().scale / currentScaling
|
||||||
|
return newScale / currentScaling
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncPaperCircleDiameter = (circle: paper.Path) => {
|
||||||
|
const nextDiameter = getPaperNodeDiameter()
|
||||||
|
const currentDiameter =
|
||||||
|
Number(circle.data?.diameter) || LEGACY_PAPER_NODE_DIAMETER
|
||||||
|
|
||||||
|
if (
|
||||||
|
Number.isFinite(currentDiameter) &&
|
||||||
|
currentDiameter > 0 &&
|
||||||
|
Math.abs(currentDiameter - nextDiameter) > 0.001
|
||||||
|
) {
|
||||||
|
circle.scale(nextDiameter / currentDiameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
circle.data = Object.assign({}, circle.data, {
|
||||||
|
diameter: nextDiameter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const getPaperCursorByMode = (
|
const getPaperCursorByMode = (
|
||||||
mode: PaperState["mode"] = usePaperStore.getState().mode
|
mode: PaperState["mode"] = usePaperStore.getState().mode
|
||||||
) => {
|
) => {
|
||||||
@@ -529,6 +564,7 @@ const createPointCircleForPath = (
|
|||||||
imageId: path.data.imageId,
|
imageId: path.data.imageId,
|
||||||
operationId: path.data.operationId,
|
operationId: path.data.operationId,
|
||||||
text: index + 1,
|
text: index + 1,
|
||||||
|
diameter: getPaperNodeDiameter(),
|
||||||
fillColor: path.data.blankColor,
|
fillColor: path.data.blankColor,
|
||||||
strokeColor: path.data.strokeColor,
|
strokeColor: path.data.strokeColor,
|
||||||
})
|
})
|
||||||
@@ -562,6 +598,7 @@ const syncPointCirclesWithPath = (path: paper.Path) => {
|
|||||||
imageId: path.data.imageId,
|
imageId: path.data.imageId,
|
||||||
operationId: path.data.operationId,
|
operationId: path.data.operationId,
|
||||||
text: index + 1,
|
text: index + 1,
|
||||||
|
diameter: getPaperNodeDiameter(),
|
||||||
fillColor: path.data.blankColor,
|
fillColor: path.data.blankColor,
|
||||||
strokeColor: path.data.strokeColor,
|
strokeColor: path.data.strokeColor,
|
||||||
})
|
})
|
||||||
@@ -1014,6 +1051,19 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
...state,
|
...state,
|
||||||
loadingData: flag,
|
loadingData: flag,
|
||||||
})),
|
})),
|
||||||
|
refreshNodeVisualSize: () => {
|
||||||
|
const group = usePaperStore.getState().group
|
||||||
|
if (!group) return
|
||||||
|
;(
|
||||||
|
group.getItems({
|
||||||
|
match: (item: paper.Item) =>
|
||||||
|
item instanceof paper.Path &&
|
||||||
|
["circle", "pathCircle"].includes(item.data?.type || ""),
|
||||||
|
}) as paper.Path[]
|
||||||
|
).forEach((circle) => {
|
||||||
|
syncPaperCircleDiameter(circle)
|
||||||
|
})
|
||||||
|
},
|
||||||
requestResizeGhost: () =>
|
requestResizeGhost: () =>
|
||||||
set((state: PaperState) => ({
|
set((state: PaperState) => ({
|
||||||
...state,
|
...state,
|
||||||
@@ -5427,6 +5477,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
const newScale = useTopToolsStore.getState().scale / currentScaling
|
const newScale = useTopToolsStore.getState().scale / currentScaling
|
||||||
myCircle.scale(newScale / currentScaling)
|
myCircle.scale(newScale / currentScaling)
|
||||||
myCircle.data = Object.assign({ type: "circle", ...option }, data)
|
myCircle.data = Object.assign({ type: "circle", ...option }, data)
|
||||||
|
syncPaperCircleDiameter(myCircle)
|
||||||
myCircle.onMouseDown = (e: { event: MouseEvent; point: paper.Point }) => {
|
myCircle.onMouseDown = (e: { event: MouseEvent; point: paper.Point }) => {
|
||||||
if (e.event && e.event.button === 2) {
|
if (e.event && e.event.button === 2) {
|
||||||
if (
|
if (
|
||||||
@@ -5844,6 +5895,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
id: number,
|
id: number,
|
||||||
color: any
|
color: any
|
||||||
) => {
|
) => {
|
||||||
|
const nodeDiameter = getPaperNodeDiameter()
|
||||||
let circle: paper.Path.Circle = new paper.Path.Circle(
|
let circle: paper.Path.Circle = new paper.Path.Circle(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
{ parent: usePaperStore.getState().group!, center: point },
|
{ parent: usePaperStore.getState().group!, center: point },
|
||||||
@@ -5851,12 +5903,13 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
fillColor: color,
|
fillColor: color,
|
||||||
// center: point,
|
// center: point,
|
||||||
strokeColor: usePaperStore.getState().toolOption?.strokeColor,
|
strokeColor: usePaperStore.getState().toolOption?.strokeColor,
|
||||||
radius: 3,
|
radius: getPaperNodeRadius(),
|
||||||
strokeScaling: false,
|
strokeScaling: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: {
|
data: {
|
||||||
type: "circle",
|
type: "circle",
|
||||||
|
diameter: nodeDiameter,
|
||||||
fillColor: color,
|
fillColor: color,
|
||||||
strokeColor: usePaperStore.getState().toolOption?.strokeColor,
|
strokeColor: usePaperStore.getState().toolOption?.strokeColor,
|
||||||
imageId: useBottomToolsStore.getState().activeImage,
|
imageId: useBottomToolsStore.getState().activeImage,
|
||||||
@@ -5868,9 +5921,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
const currentScaling = usePaperStore.getState().group!.scaling.x
|
circle.scale(getPaperNodeScaleFactor())
|
||||||
const newScale = useTopToolsStore.getState().scale / currentScaling
|
|
||||||
circle.scale(newScale / currentScaling)
|
|
||||||
circle.onMouseDown = (e: { event: MouseEvent; point: paper.Point }) => {
|
circle.onMouseDown = (e: { event: MouseEvent; point: paper.Point }) => {
|
||||||
if (e.event && e.event.button === 2) {
|
if (e.event && e.event.button === 2) {
|
||||||
if (
|
if (
|
||||||
@@ -6051,8 +6102,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
id: number,
|
id: number,
|
||||||
color: any
|
color: any
|
||||||
) => {
|
) => {
|
||||||
const currentScaling = usePaperStore.getState().group!.scaling.x
|
const nodeDiameter = getPaperNodeDiameter()
|
||||||
const newScale = useTopToolsStore.getState().scale / currentScaling
|
|
||||||
let circle: paper.Path.Circle = new paper.Path.Circle(
|
let circle: paper.Path.Circle = new paper.Path.Circle(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
{ parent: usePaperStore.getState().group!, center: point },
|
{ parent: usePaperStore.getState().group!, center: point },
|
||||||
@@ -6060,15 +6110,16 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
fillColor: color,
|
fillColor: color,
|
||||||
// center: point,
|
// center: point,
|
||||||
strokeColor: "#FFF",
|
strokeColor: "#FFF",
|
||||||
radius: 3,
|
strokeWidth: 2,
|
||||||
|
radius: getPaperNodeRadius(),
|
||||||
strokeScaling: false,
|
strokeScaling: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: { index, type: "pathCircle", id },
|
data: { index, type: "pathCircle", id, diameter: nodeDiameter },
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
circle.scale(newScale / currentScaling)
|
circle.scale(getPaperNodeScaleFactor())
|
||||||
circle.onMouseEnter = (_e: any) => {
|
circle.onMouseEnter = (_e: any) => {
|
||||||
hoveredPathCircleInfo = {
|
hoveredPathCircleInfo = {
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -6,6 +6,17 @@ import { useObjectStore } from "./store"
|
|||||||
import { useBottomToolsStore } from "./useBottomToolsStore"
|
import { useBottomToolsStore } from "./useBottomToolsStore"
|
||||||
import { safeClone } from "./utils/clone"
|
import { safeClone } from "./utils/clone"
|
||||||
|
|
||||||
|
export const NODE_SIZE_MIN = 6
|
||||||
|
export const NODE_SIZE_MAX = 24
|
||||||
|
export const DEFAULT_NODE_SIZE = 10
|
||||||
|
|
||||||
|
const clampNodeSize = (value: number) => {
|
||||||
|
const nextValue = Number.isFinite(value)
|
||||||
|
? Math.round(value)
|
||||||
|
: DEFAULT_NODE_SIZE
|
||||||
|
return Math.min(NODE_SIZE_MAX, Math.max(NODE_SIZE_MIN, nextValue))
|
||||||
|
}
|
||||||
|
|
||||||
interface TopToolsState {
|
interface TopToolsState {
|
||||||
// 标注页面是否仅查看
|
// 标注页面是否仅查看
|
||||||
isView: boolean
|
isView: boolean
|
||||||
@@ -34,6 +45,8 @@ interface TopToolsState {
|
|||||||
setAssistToolEnabled: (val: boolean) => void
|
setAssistToolEnabled: (val: boolean) => void
|
||||||
assistToolSize: number
|
assistToolSize: number
|
||||||
setAssistToolSize: (val: number) => void
|
setAssistToolSize: (val: number) => void
|
||||||
|
nodeSize: number
|
||||||
|
setNodeSize: (val: number) => void
|
||||||
showTags: boolean
|
showTags: boolean
|
||||||
setShowTags: (val: boolean) => void
|
setShowTags: (val: boolean) => void
|
||||||
showTagsConfigs: string[]
|
showTagsConfigs: string[]
|
||||||
@@ -94,6 +107,7 @@ const initialTopToolsState = {
|
|||||||
crosshairStatus: "hidden" as "hidden" | "line" | "carve",
|
crosshairStatus: "hidden" as "hidden" | "line" | "carve",
|
||||||
assistToolEnabled: false,
|
assistToolEnabled: false,
|
||||||
assistToolSize: 10,
|
assistToolSize: 10,
|
||||||
|
nodeSize: DEFAULT_NODE_SIZE,
|
||||||
drawOption: "default" as "default" | "intersect" | "unite",
|
drawOption: "default" as "default" | "intersect" | "unite",
|
||||||
saveCurrentScale: false,
|
saveCurrentScale: false,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
@@ -183,6 +197,12 @@ export const useTopToolsStore = create<TopToolsState>()(
|
|||||||
...state,
|
...state,
|
||||||
assistToolSize: Math.max(1, val),
|
assistToolSize: Math.max(1, val),
|
||||||
})),
|
})),
|
||||||
|
nodeSize: initialTopToolsState.nodeSize,
|
||||||
|
setNodeSize: (val) =>
|
||||||
|
set((state: TopToolsState) => ({
|
||||||
|
...state,
|
||||||
|
nodeSize: clampNodeSize(val),
|
||||||
|
})),
|
||||||
showTags: false,
|
showTags: false,
|
||||||
setShowTags: (val) =>
|
setShowTags: (val) =>
|
||||||
set((state: TopToolsState) => ({
|
set((state: TopToolsState) => ({
|
||||||
|
|||||||
Reference in New Issue
Block a user