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 =
"width 160ms ease, min-width 160ms ease, opacity 160ms ease"
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
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 GLOBAL_LOADING_Z_INDEX = 900
const videoMimeByExt: Record<string, string> = {
@@ -233,7 +283,7 @@ const LabelPage = ({
const qaToolContainerRef = useRef<any>(null)
const [isConfirmSave, setIsConfirmSave] = 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 [hasReadyVideoFrame, setHasReadyVideoFrame] = useState(false)
const [sourceVideoNames, setSourceVideoNames] = useState<string[]>([])
@@ -2479,51 +2529,35 @@ const LabelPage = ({
// 更新Splitter状态
const updateSplitterSizes = useCallback(() => {
console.log(
"document.documentElement.clientWidth",
document.documentElement.clientWidth
const availableWidth = Math.max(
document.documentElement.clientWidth - leftWidth - 4,
0
)
const len = document.documentElement.clientWidth - 4
let arr = [len, 0, 0, 0, 0, 0]
const flags = [
const flags: boolean[] = [
showTaskList,
showGroupList,
showDescList && projectDetail && projectDetail.label_type === 5,
showDescList && projectDetail && projectDetail.label_type === 6,
(showDescList && projectDetail && projectDetail.label_type === 5) ||
false,
(showDescList && projectDetail && projectDetail.label_type === 6) ||
false,
showObjectList,
]
let count = 0
flags.forEach((flag) => {
if (flag) count++
})
if (count === 1 || count === 2) {
arr[0] = count === 1 ? len * 0.8 : len * 0.6
flags.forEach((flag, index) => {
if (flag) {
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])
setSizes(allocateRightPanelSizes(availableWidth, flags))
}, [
leftWidth,
projectDetail,
showDescList,
showGroupList,
showObjectList,
showTaskList,
])
useEffect(() => {
updateSplitterSizes()
window.addEventListener("resize", updateSplitterSizes)
return () => {
window.removeEventListener("resize", updateSplitterSizes)
}
}, [updateSplitterSizes])
useEffect(() => {
@@ -2702,7 +2736,7 @@ const LabelPage = ({
</Box>
<Flex w="calc(100% - 4px)" h={mainBoxHeight}>
{/* <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">
<Flex h="100%" w="100%">
<Flex
@@ -2780,7 +2814,7 @@ const LabelPage = ({
</Box>
<Box
w={sizes[1]}
miw={showTaskList ? 300 : 0}
miw={showTaskList ? sizes[1] : 0}
style={{
position: "relative",
flexShrink: 0,
@@ -2788,10 +2822,11 @@ const LabelPage = ({
opacity: showTaskList ? 1 : 0,
visibility: showTaskList ? "visible" : "hidden",
pointerEvents: showTaskList ? "auto" : "none",
borderLeft: showTaskList ? RIGHT_PANEL_SEPARATOR : "none",
transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE,
}}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[1], 300))}>
<Box style={getRightPanelViewportStyle(sizes[1])}>
<RightTaskTools
projectDetail={projectDetail}
project_id={projectId}
@@ -2801,7 +2836,7 @@ const LabelPage = ({
</Box>
<Box
w={sizes[2]}
miw={showGroupList ? 200 : 0}
miw={showGroupList ? sizes[2] : 0}
style={{
position: "relative",
flexShrink: 0,
@@ -2809,10 +2844,11 @@ const LabelPage = ({
opacity: showGroupList ? 1 : 0,
visibility: showGroupList ? "visible" : "hidden",
pointerEvents: showGroupList ? "auto" : "none",
borderLeft: showGroupList ? RIGHT_PANEL_SEPARATOR : "none",
transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE,
}}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[2], 200))}>
<Box style={getRightPanelViewportStyle(sizes[2])}>
<RightGroupTools
labelState={labelState}
projectDetail={projectDetail}
@@ -2823,7 +2859,7 @@ const LabelPage = ({
w={sizes[3]}
miw={
showDescList && projectDetail && projectDetail.label_type === 5
? 350
? sizes[3]
: 0
}
style={{
@@ -2842,10 +2878,14 @@ const LabelPage = ({
showDescList && projectDetail && projectDetail.label_type === 5
? "auto"
: "none",
borderLeft:
showDescList && projectDetail && projectDetail.label_type === 5
? RIGHT_PANEL_SEPARATOR
: "none",
transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE,
}}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[3], 350))}>
<Box style={getRightPanelViewportStyle(sizes[3])}>
<RightDescTools taskDetail={taskDetail} />
</Box>
</Box>
@@ -2853,7 +2893,7 @@ const LabelPage = ({
w={sizes[4]}
miw={
showDescList && projectDetail && projectDetail.label_type === 6
? 350
? sizes[4]
: 0
}
style={{
@@ -2872,16 +2912,20 @@ const LabelPage = ({
showDescList && projectDetail && projectDetail.label_type === 6
? "auto"
: "none",
borderLeft:
showDescList && projectDetail && projectDetail.label_type === 6
? RIGHT_PANEL_SEPARATOR
: "none",
transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE,
}}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[4], 350))}>
<Box style={getRightPanelViewportStyle(sizes[4])}>
<RightQATools ref={qaToolContainerRef} taskDetail={taskDetail} />
</Box>
</Box>
<Box
w={sizes[5]}
miw={showObjectList ? 350 : 0}
miw={showObjectList ? sizes[5] : 0}
style={{
position: "relative",
flexShrink: 0,
@@ -2889,10 +2933,11 @@ const LabelPage = ({
opacity: showObjectList ? 1 : 0,
visibility: showObjectList ? "visible" : "hidden",
pointerEvents: showObjectList ? "auto" : "none",
borderLeft: showObjectList ? RIGHT_PANEL_SEPARATOR : "none",
transition: RIGHT_PANEL_TRANSITION,
willChange: RIGHT_PANEL_WILL_CHANGE,
}}>
<Box style={getRightPanelViewportStyle(Math.max(sizes[5], 350))}>
<Box style={getRightPanelViewportStyle(sizes[5])}>
<RightObjectTools
taskDetail={taskDetail}
labelState={labelState}

View File

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

View File

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

View File

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