fix(tool): fix size bug

This commit is contained in:
zhangheng
2026-04-15 17:13:28 +08:00
parent da6a33a368
commit dfd5f0fca1
4 changed files with 136 additions and 63 deletions

View File

@@ -83,6 +83,11 @@ let latestTaskDetailRequestSeq = 0
const RIGHT_PANEL_TRANSITION = const RIGHT_PANEL_TRANSITION =
"width 160ms ease, min-width 160ms ease, opacity 160ms ease" "width 160ms ease, min-width 160ms ease, opacity 160ms ease"
const RIGHT_PANEL_WILL_CHANGE = "width, min-width, opacity" const RIGHT_PANEL_WILL_CHANGE = "width, min-width, opacity"
const RIGHT_PANEL_SEPARATOR =
"1px solid light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))"
const RIGHT_PANEL_SOFT_MAIN_MIN_WIDTH = 420
const RIGHT_PANEL_HARD_MAIN_MIN_WIDTH = 260
const RIGHT_PANEL_TARGET_WIDTH = 350
// utils // utils
const getRectPoints = ([sx, sy, w, h]: number[]) => { const getRectPoints = ([sx, sy, w, h]: number[]) => {
@@ -111,6 +116,51 @@ const getRightPanelViewportStyle = (width: number) => {
} }
} }
const allocateRightPanelSizes = (
availableWidth: number,
visibleFlags: boolean[]
) => {
const resolvedWidth = Math.max(0, Math.round(availableWidth))
const nextSizes = [resolvedWidth, 0, 0, 0, 0, 0]
const activeIndexes = visibleFlags.reduce<number[]>((result, flag, index) => {
if (flag) result.push(index + 1)
return result
}, [])
if (!activeIndexes.length) return nextSizes
const activeCount = activeIndexes.length
const softPanelBudget = Math.max(
0,
resolvedWidth - RIGHT_PANEL_SOFT_MAIN_MIN_WIDTH
)
const hardPanelBudget = Math.max(
0,
resolvedWidth - RIGHT_PANEL_HARD_MAIN_MIN_WIDTH
)
let panelWidth = Math.min(
RIGHT_PANEL_TARGET_WIDTH,
Math.floor(softPanelBudget / activeCount)
)
if (panelWidth < RIGHT_PANEL_TARGET_WIDTH) {
panelWidth = Math.min(
RIGHT_PANEL_TARGET_WIDTH,
Math.floor(hardPanelBudget / activeCount)
)
}
panelWidth = Math.max(0, panelWidth)
activeIndexes.forEach((index) => {
nextSizes[index] = panelWidth
})
const rightPanelTotalWidth = panelWidth * activeCount
nextSizes[0] = Math.max(0, resolvedWidth - rightPanelTotalWidth)
return nextSizes
}
const videoExtPattern = /\.(mp4|mov|avi|mkv|webm|h264|264|ts|m4v)$/i const videoExtPattern = /\.(mp4|mov|avi|mkv|webm|h264|264|ts|m4v)$/i
const GLOBAL_LOADING_Z_INDEX = 900 const GLOBAL_LOADING_Z_INDEX = 900
const videoMimeByExt: Record<string, string> = { const videoMimeByExt: Record<string, string> = {
@@ -233,7 +283,7 @@ const LabelPage = ({
const qaToolContainerRef = useRef<any>(null) const qaToolContainerRef = useRef<any>(null)
const [isConfirmSave, setIsConfirmSave] = useState(false) const [isConfirmSave, setIsConfirmSave] = useState(false)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [sizes, setSizes] = useState<number[]>([]) const [sizes, setSizes] = useState<number[]>([0, 0, 0, 0, 0, 0])
const [videoFetchPendingCount, setVideoFetchPendingCount] = useState(0) const [videoFetchPendingCount, setVideoFetchPendingCount] = useState(0)
const [hasReadyVideoFrame, setHasReadyVideoFrame] = useState(false) const [hasReadyVideoFrame, setHasReadyVideoFrame] = useState(false)
const [sourceVideoNames, setSourceVideoNames] = useState<string[]>([]) const [sourceVideoNames, setSourceVideoNames] = useState<string[]>([])
@@ -2479,51 +2529,35 @@ const LabelPage = ({
// 更新Splitter状态 // 更新Splitter状态
const updateSplitterSizes = useCallback(() => { const updateSplitterSizes = useCallback(() => {
console.log( const availableWidth = Math.max(
"document.documentElement.clientWidth", document.documentElement.clientWidth - leftWidth - 4,
document.documentElement.clientWidth 0
) )
const flags: boolean[] = [
const len = document.documentElement.clientWidth - 4
let arr = [len, 0, 0, 0, 0, 0]
const flags = [
showTaskList, showTaskList,
showGroupList, showGroupList,
showDescList && projectDetail && projectDetail.label_type === 5, (showDescList && projectDetail && projectDetail.label_type === 5) ||
showDescList && projectDetail && projectDetail.label_type === 6, false,
(showDescList && projectDetail && projectDetail.label_type === 6) ||
false,
showObjectList, showObjectList,
] ]
let count = 0 setSizes(allocateRightPanelSizes(availableWidth, flags))
flags.forEach((flag) => { }, [
if (flag) count++ leftWidth,
}) projectDetail,
if (count === 1 || count === 2) { showDescList,
arr[0] = count === 1 ? len * 0.8 : len * 0.6 showGroupList,
flags.forEach((flag, index) => { showObjectList,
if (flag) { showTaskList,
arr[index + 1] = len * 0.2 ])
}
})
} else if (count === 3) {
arr[0] = len * 0.55
flags.forEach((flag, index) => {
if (flag) {
arr[index + 1] = len * 0.15
}
})
} else if (count === 4) {
arr[0] = len * 0.6
flags.forEach((flag, index) => {
if (flag) {
arr[index + 1] = len * 0.1
}
})
}
setSizes(arr)
}, [projectDetail, showDescList, showGroupList, showObjectList, showTaskList])
useEffect(() => { useEffect(() => {
updateSplitterSizes() updateSplitterSizes()
window.addEventListener("resize", updateSplitterSizes)
return () => {
window.removeEventListener("resize", updateSplitterSizes)
}
}, [updateSplitterSizes]) }, [updateSplitterSizes])
useEffect(() => { useEffect(() => {
@@ -2702,7 +2736,7 @@ const LabelPage = ({
</Box> </Box>
<Flex w="calc(100% - 4px)" h={mainBoxHeight}> <Flex w="calc(100% - 4px)" h={mainBoxHeight}>
{/* <Flex h="100%" w={"100%"}> */} {/* <Flex h="100%" w={"100%"}> */}
<Box w={sizes[0] - leftWidth} style={{ flexShrink: 0 }}> <Box w={sizes[0]} style={{ flexShrink: 0, minWidth: 0 }}>
<Box h="100%" id="resize-container"> <Box h="100%" id="resize-container">
<Flex h="100%" w="100%"> <Flex h="100%" w="100%">
<Flex <Flex
@@ -2780,7 +2814,7 @@ const LabelPage = ({
</Box> </Box>
<Box <Box
w={sizes[1]} w={sizes[1]}
miw={showTaskList ? 300 : 0} miw={showTaskList ? sizes[1] : 0}
style={{ style={{
position: "relative", position: "relative",
flexShrink: 0, flexShrink: 0,
@@ -2788,10 +2822,11 @@ const LabelPage = ({
opacity: showTaskList ? 1 : 0, opacity: showTaskList ? 1 : 0,
visibility: showTaskList ? "visible" : "hidden", visibility: showTaskList ? "visible" : "hidden",
pointerEvents: showTaskList ? "auto" : "none", pointerEvents: showTaskList ? "auto" : "none",
borderLeft: showTaskList ? RIGHT_PANEL_SEPARATOR : "none",
transition: RIGHT_PANEL_TRANSITION, transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE, willChange: RIGHT_PANEL_WILL_CHANGE,
}}> }}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[1], 300))}> <Box style={getRightPanelViewportStyle(sizes[1])}>
<RightTaskTools <RightTaskTools
projectDetail={projectDetail} projectDetail={projectDetail}
project_id={projectId} project_id={projectId}
@@ -2801,7 +2836,7 @@ const LabelPage = ({
</Box> </Box>
<Box <Box
w={sizes[2]} w={sizes[2]}
miw={showGroupList ? 200 : 0} miw={showGroupList ? sizes[2] : 0}
style={{ style={{
position: "relative", position: "relative",
flexShrink: 0, flexShrink: 0,
@@ -2809,10 +2844,11 @@ const LabelPage = ({
opacity: showGroupList ? 1 : 0, opacity: showGroupList ? 1 : 0,
visibility: showGroupList ? "visible" : "hidden", visibility: showGroupList ? "visible" : "hidden",
pointerEvents: showGroupList ? "auto" : "none", pointerEvents: showGroupList ? "auto" : "none",
borderLeft: showGroupList ? RIGHT_PANEL_SEPARATOR : "none",
transition: RIGHT_PANEL_TRANSITION, transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE, willChange: RIGHT_PANEL_WILL_CHANGE,
}}> }}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[2], 200))}> <Box style={getRightPanelViewportStyle(sizes[2])}>
<RightGroupTools <RightGroupTools
labelState={labelState} labelState={labelState}
projectDetail={projectDetail} projectDetail={projectDetail}
@@ -2823,7 +2859,7 @@ const LabelPage = ({
w={sizes[3]} w={sizes[3]}
miw={ miw={
showDescList && projectDetail && projectDetail.label_type === 5 showDescList && projectDetail && projectDetail.label_type === 5
? 350 ? sizes[3]
: 0 : 0
} }
style={{ style={{
@@ -2842,10 +2878,14 @@ const LabelPage = ({
showDescList && projectDetail && projectDetail.label_type === 5 showDescList && projectDetail && projectDetail.label_type === 5
? "auto" ? "auto"
: "none", : "none",
borderLeft:
showDescList && projectDetail && projectDetail.label_type === 5
? RIGHT_PANEL_SEPARATOR
: "none",
transition: RIGHT_PANEL_TRANSITION, transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE, willChange: RIGHT_PANEL_WILL_CHANGE,
}}> }}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[3], 350))}> <Box style={getRightPanelViewportStyle(sizes[3])}>
<RightDescTools taskDetail={taskDetail} /> <RightDescTools taskDetail={taskDetail} />
</Box> </Box>
</Box> </Box>
@@ -2853,7 +2893,7 @@ const LabelPage = ({
w={sizes[4]} w={sizes[4]}
miw={ miw={
showDescList && projectDetail && projectDetail.label_type === 6 showDescList && projectDetail && projectDetail.label_type === 6
? 350 ? sizes[4]
: 0 : 0
} }
style={{ style={{
@@ -2872,16 +2912,20 @@ const LabelPage = ({
showDescList && projectDetail && projectDetail.label_type === 6 showDescList && projectDetail && projectDetail.label_type === 6
? "auto" ? "auto"
: "none", : "none",
borderLeft:
showDescList && projectDetail && projectDetail.label_type === 6
? RIGHT_PANEL_SEPARATOR
: "none",
transition: RIGHT_PANEL_TRANSITION, transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE, willChange: RIGHT_PANEL_WILL_CHANGE,
}}> }}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[4], 350))}> <Box style={getRightPanelViewportStyle(sizes[4])}>
<RightQATools ref={qaToolContainerRef} taskDetail={taskDetail} /> <RightQATools ref={qaToolContainerRef} taskDetail={taskDetail} />
</Box> </Box>
</Box> </Box>
<Box <Box
w={sizes[5]} w={sizes[5]}
miw={showObjectList ? 350 : 0} miw={showObjectList ? sizes[5] : 0}
style={{ style={{
position: "relative", position: "relative",
flexShrink: 0, flexShrink: 0,
@@ -2889,10 +2933,11 @@ const LabelPage = ({
opacity: showObjectList ? 1 : 0, opacity: showObjectList ? 1 : 0,
visibility: showObjectList ? "visible" : "hidden", visibility: showObjectList ? "visible" : "hidden",
pointerEvents: showObjectList ? "auto" : "none", pointerEvents: showObjectList ? "auto" : "none",
borderLeft: showObjectList ? RIGHT_PANEL_SEPARATOR : "none",
transition: RIGHT_PANEL_TRANSITION, transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE, willChange: RIGHT_PANEL_WILL_CHANGE,
}}> }}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[5], 350))}> <Box style={getRightPanelViewportStyle(sizes[5])}>
<RightObjectTools <RightObjectTools
taskDetail={taskDetail} taskDetail={taskDetail}
labelState={labelState} labelState={labelState}

View File

@@ -222,6 +222,7 @@ const PaperContainer = (
} }
if ( if (
!useTopToolsStore.getState().saveCurrentScale &&
RESIZE_INTERPOLATION_DURATION_MS > 0 && RESIZE_INTERPOLATION_DURATION_MS > 0 &&
firstRender && firstRender &&
lastSize?.clientWidth && lastSize?.clientWidth &&
@@ -3132,6 +3133,8 @@ const PaperContainer = (
const activeImageChanged = prevActiveImageRef.current !== activeImage const activeImageChanged = prevActiveImageRef.current !== activeImage
prevActiveImageRef.current = activeImage prevActiveImageRef.current = activeImage
const hasPicRaster = getPicRasters(currentGroup).length > 0 const hasPicRaster = getPicRasters(currentGroup).length > 0
const preserveViewportOnLayoutResize =
useTopToolsStore.getState().saveCurrentScale
if (!useTopToolsStore.getState().saveCurrentScale) { if (!useTopToolsStore.getState().saveCurrentScale) {
currentGroup.scaling = new paper.Point(1, 1) currentGroup.scaling = new paper.Point(1, 1)
@@ -3143,6 +3146,12 @@ const PaperContainer = (
} }
if (!activeImageChanged) { if (!activeImageChanged) {
if (
preserveViewportOnLayoutResize &&
(hasPicRaster || rasterLoadingImageRef.current === activeImage)
) {
return
}
if (resizeCurrentImage()) { if (resizeCurrentImage()) {
return return
} }

View File

@@ -30,7 +30,7 @@ import {
Spline, Spline,
} from "lucide-react" } from "lucide-react"
import paper from "paper" import paper from "paper"
import { useCallback, useState } from "react" import { useCallback, useMemo, useState } from "react"
import { Project } from "../api/project/typing" import { Project } from "../api/project/typing"
import { Task } from "../api/task/typing" import { Task } from "../api/task/typing"
import { LabelState } from "../LabelNossr" import { LabelState } from "../LabelNossr"
@@ -151,6 +151,7 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
continuePolygonTarget?.imageId === activeImage continuePolygonTarget?.imageId === activeImage
? continuePolygonTarget.objectId ? continuePolygonTarget.objectId
: null : null
const objectOperations = useTopToolsStore((state) => state.objectOperations)
const getOperationChildren = useCallback( const getOperationChildren = useCallback(
(imageId: string, operationId: string) => { (imageId: string, operationId: string) => {
@@ -415,9 +416,13 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
[activeImage] [activeImage]
) )
const activeImageOperations = (labelState.get(activeImage) || []).filter( const activeImageOperations = useMemo(() => {
(operationId) => getOperationChildren(activeImage, operationId).length const schemaOperationIds = objectOperations.map((item) =>
item.category_id.toString()
) )
const imageOperationIds = labelState.get(activeImage) || []
return Array.from(new Set([...schemaOperationIds, ...imageOperationIds]))
}, [activeImage, labelState, objectOperations])
const isObjectHidden = (imageId: string, objectId: number) => { const isObjectHidden = (imageId: string, objectId: number) => {
return pathStatus[imageId + objectId]?.["HIDE"] ?? false return pathStatus[imageId + objectId]?.["HIDE"] ?? false
@@ -558,9 +563,17 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
return ( return (
<Box h="100%" w="100%"> <Box h="100%" w="100%">
<Flex direction="column" h="100%" gap="xs"> <Flex direction="column" h="100%" gap="xs">
<Flex justify="space-between" align="center" px="md" py="xs"> <Flex
<Group gap="xs"> justify="space-between"
align="center"
wrap="nowrap"
gap={6}
px="md"
py="xs"
style={{ minWidth: 0 }}>
<Group gap={6} wrap="nowrap" style={{ minWidth: 0, flexShrink: 0 }}>
<ActionIcon <ActionIcon
size="sm"
variant="subtle" variant="subtle"
aria-label={areAllObjectsHidden ? "显示全部对象" : "隐藏全部对象"} aria-label={areAllObjectsHidden ? "显示全部对象" : "隐藏全部对象"}
onClick={() => { onClick={() => {
@@ -571,20 +584,23 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
}}> }}>
{areAllObjectsHidden ? <EyeOff size={16} /> : <Eye size={16} />} {areAllObjectsHidden ? <EyeOff size={16} /> : <Eye size={16} />}
</ActionIcon> </ActionIcon>
<Title order={4} size="h4"> <Title
order={5}
size="h5"
style={{ whiteSpace: "nowrap", lineHeight: 1.1 }}>
</Title> </Title>
</Group> </Group>
<Group gap="xs"> <Group gap={6} wrap="nowrap" style={{ minWidth: 0, flexShrink: 0 }}>
<TextInput <TextInput
w={96} w={72}
size="xs" size="xs"
placeholder="输入ID" placeholder="输入ID"
value={searchId} value={searchId}
onChange={(e) => setSearchId(e.target.value)} onChange={(e) => setSearchId(e.target.value)}
onKeyDown={handleSelectedBySearchId} onKeyDown={handleSelectedBySearchId}
/> />
<Group gap={4}> <Group gap={2} wrap="nowrap">
{[3, 2, 1, 0].map((type, index) => ( {[3, 2, 1, 0].map((type, index) => (
<Checkbox <Checkbox
key={type} key={type}
@@ -603,6 +619,7 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
))} ))}
</Group> </Group>
<ActionIcon <ActionIcon
size="sm"
variant="subtle" variant="subtle"
onClick={() => { onClick={() => {
updateImageStatus( updateImageStatus(

View File

@@ -54,8 +54,8 @@ import {
MousePointer, MousePointer,
Paintbrush, Paintbrush,
Pen, Pen,
SquarePen,
SquareDashedMousePointer, SquareDashedMousePointer,
SquarePen,
Tag, Tag,
Timer, Timer,
} from "lucide-react" } from "lucide-react"
@@ -263,14 +263,15 @@ const TopTools = (
const nextVisible = !visible const nextVisible = !visible
const nextCount = visibleRightPanelCount + (nextVisible ? 1 : -1) const nextCount = visibleRightPanelCount + (nextVisible ? 1 : -1)
if ( if (
(visibleRightPanelCount === 0 && nextCount === 1) || !saveCurrentScale &&
(visibleRightPanelCount === 1 && nextCount === 0) ((visibleRightPanelCount === 0 && nextCount === 1) ||
(visibleRightPanelCount === 1 && nextCount === 0))
) { ) {
requestResizeGhost() requestResizeGhost()
} }
setter(nextVisible) setter(nextVisible)
}, },
[requestResizeGhost, visibleRightPanelCount] [requestResizeGhost, saveCurrentScale, visibleRightPanelCount]
) )
// 当前是否可以操作功能按键 // 当前是否可以操作功能按键
@@ -1118,6 +1119,7 @@ const TopTools = (
}) })
try { try {
await handleSave() await handleSave()
notifications.hide("save")
} catch (error) { } catch (error) {
console.log(error) console.log(error)
return return