Merge branch 'zh' into 'main'
Zh See merge request prism/lable/labelimage!13
This commit is contained in:
@@ -38,6 +38,31 @@ import { useRouter, useSearchParams } from "next/navigation"
|
|||||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
import { useCallback, useEffect, useMemo, useState } from "react"
|
||||||
import TaskStatusTag from "./components/TaskStatusTag"
|
import TaskStatusTag from "./components/TaskStatusTag"
|
||||||
|
|
||||||
|
const EMPTY_TASK_SIZE: Task.SizeProps = Object.freeze({
|
||||||
|
object_size: 0,
|
||||||
|
valid_size: 0,
|
||||||
|
first_comment_size: 0,
|
||||||
|
second_comment_size: 0,
|
||||||
|
new_size: 0,
|
||||||
|
prelabel_size: 0,
|
||||||
|
prelabel_modify_size: 0,
|
||||||
|
dynamic_size: 0,
|
||||||
|
static_size: 0,
|
||||||
|
review_size: 0,
|
||||||
|
review_dynamic_size: 0,
|
||||||
|
review_static_size: 0,
|
||||||
|
key_frame_size: 0,
|
||||||
|
question_size: 0,
|
||||||
|
total_qa_group_size: 0,
|
||||||
|
single_qa_group_size: 0,
|
||||||
|
multiple_qa_group_size: 0,
|
||||||
|
new_qa_group_size: 0,
|
||||||
|
new_single_qa_group_size: 0,
|
||||||
|
new_multiple_qa_group_size: 0,
|
||||||
|
review_question_size: 0,
|
||||||
|
comment_question_size: 0,
|
||||||
|
})
|
||||||
|
|
||||||
function createInitialFilters() {
|
function createInitialFilters() {
|
||||||
return {
|
return {
|
||||||
search_id: "",
|
search_id: "",
|
||||||
@@ -67,6 +92,7 @@ export default function OwnTaskTableContainer(props: {
|
|||||||
const user_id = usePermissionStore((s) => s.user_id)
|
const user_id = usePermissionStore((s) => s.user_id)
|
||||||
|
|
||||||
const [total, setTotal] = useState(0)
|
const [total, setTotal] = useState(0)
|
||||||
|
const [totalSize, setTotalSize] = useState<Task.SizeProps>(EMPTY_TASK_SIZE)
|
||||||
|
|
||||||
const [pageNumber, setPageNumber] = useState(1)
|
const [pageNumber, setPageNumber] = useState(1)
|
||||||
const [pageSize, setPageSize] = useState(15)
|
const [pageSize, setPageSize] = useState(15)
|
||||||
@@ -130,9 +156,11 @@ export default function OwnTaskTableContainer(props: {
|
|||||||
const res = await getTaskList(appliedParams)
|
const res = await getTaskList(appliedParams)
|
||||||
setRecords(res?.task_list ?? [])
|
setRecords(res?.task_list ?? [])
|
||||||
setTotal(res?.total_items ?? 0)
|
setTotal(res?.total_items ?? 0)
|
||||||
|
setTotalSize(res?.total_size ?? EMPTY_TASK_SIZE)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setRecords([])
|
setRecords([])
|
||||||
setTotal(0)
|
setTotal(0)
|
||||||
|
setTotalSize(EMPTY_TASK_SIZE)
|
||||||
notifications.show({
|
notifications.show({
|
||||||
color: "red",
|
color: "red",
|
||||||
title: "加载失败",
|
title: "加载失败",
|
||||||
@@ -201,6 +229,7 @@ export default function OwnTaskTableContainer(props: {
|
|||||||
accessor: "id",
|
accessor: "id",
|
||||||
title: "任务ID",
|
title: "任务ID",
|
||||||
width: 100,
|
width: 100,
|
||||||
|
footer: "总计",
|
||||||
render: (record) => (
|
render: (record) => (
|
||||||
<Button
|
<Button
|
||||||
variant="transparent"
|
variant="transparent"
|
||||||
@@ -243,30 +272,35 @@ export default function OwnTaskTableContainer(props: {
|
|||||||
accessor: "label_object_size.object_size",
|
accessor: "label_object_size.object_size",
|
||||||
title: "对象总数",
|
title: "对象总数",
|
||||||
width: 110,
|
width: 110,
|
||||||
|
footer: totalSize.object_size,
|
||||||
render: (record) => record.label_object_size?.object_size ?? "-",
|
render: (record) => record.label_object_size?.object_size ?? "-",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: "label_object_size.valid_size",
|
accessor: "label_object_size.valid_size",
|
||||||
title: "有效数",
|
title: "有效数",
|
||||||
width: 100,
|
width: 100,
|
||||||
|
footer: totalSize.valid_size,
|
||||||
render: (record) => record.label_object_size?.valid_size ?? "-",
|
render: (record) => record.label_object_size?.valid_size ?? "-",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: "label_object_size.new_size",
|
accessor: "label_object_size.new_size",
|
||||||
title: "新增数",
|
title: "新增数",
|
||||||
width: 100,
|
width: 100,
|
||||||
|
footer: totalSize.new_size,
|
||||||
render: (record) => record.label_object_size?.new_size ?? "-",
|
render: (record) => record.label_object_size?.new_size ?? "-",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: "label_object_size.prelabel_size",
|
accessor: "label_object_size.prelabel_size",
|
||||||
title: "预标注总数",
|
title: "预标注总数",
|
||||||
width: 120,
|
width: 120,
|
||||||
|
footer: totalSize.prelabel_size,
|
||||||
render: (record) => record.label_object_size?.prelabel_size ?? "-",
|
render: (record) => record.label_object_size?.prelabel_size ?? "-",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: "label_object_size.prelabel_modify_size",
|
accessor: "label_object_size.prelabel_modify_size",
|
||||||
title: "预标注修改数",
|
title: "预标注修改数",
|
||||||
width: 130,
|
width: 130,
|
||||||
|
footer: totalSize.prelabel_modify_size,
|
||||||
render: (record) =>
|
render: (record) =>
|
||||||
record.label_object_size?.prelabel_modify_size ?? "-",
|
record.label_object_size?.prelabel_modify_size ?? "-",
|
||||||
},
|
},
|
||||||
@@ -274,18 +308,20 @@ export default function OwnTaskTableContainer(props: {
|
|||||||
accessor: "label_object_size.first_comment_size",
|
accessor: "label_object_size.first_comment_size",
|
||||||
title: "批注一轮",
|
title: "批注一轮",
|
||||||
width: 110,
|
width: 110,
|
||||||
|
footer: totalSize.first_comment_size,
|
||||||
render: (record) => record.label_object_size?.first_comment_size ?? "-",
|
render: (record) => record.label_object_size?.first_comment_size ?? "-",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: "label_object_size.second_comment_size",
|
accessor: "label_object_size.second_comment_size",
|
||||||
title: "批注二轮",
|
title: "批注二轮",
|
||||||
width: 110,
|
width: 110,
|
||||||
|
footer: totalSize.second_comment_size,
|
||||||
render: (record) =>
|
render: (record) =>
|
||||||
record.label_object_size?.second_comment_size ?? "-",
|
record.label_object_size?.second_comment_size ?? "-",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
return cols
|
return cols
|
||||||
}, [info, projectId, router, setBackProps, type])
|
}, [info, projectId, router, setBackProps, totalSize, type])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="sm" style={{ flex: 1, minHeight: 0 }}>
|
<Stack gap="sm" style={{ flex: 1, minHeight: 0 }}>
|
||||||
|
|||||||
@@ -122,6 +122,31 @@ const SORTABLE_TASK_SIZE_COLUMNS: Array<{
|
|||||||
{ accessor: "second_comment_size", title: "批注数(2)", width: 120 },
|
{ accessor: "second_comment_size", title: "批注数(2)", width: 120 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const EMPTY_TASK_SIZE: Task.SizeProps = Object.freeze({
|
||||||
|
object_size: 0,
|
||||||
|
valid_size: 0,
|
||||||
|
first_comment_size: 0,
|
||||||
|
second_comment_size: 0,
|
||||||
|
new_size: 0,
|
||||||
|
prelabel_size: 0,
|
||||||
|
prelabel_modify_size: 0,
|
||||||
|
dynamic_size: 0,
|
||||||
|
static_size: 0,
|
||||||
|
review_size: 0,
|
||||||
|
review_dynamic_size: 0,
|
||||||
|
review_static_size: 0,
|
||||||
|
key_frame_size: 0,
|
||||||
|
question_size: 0,
|
||||||
|
total_qa_group_size: 0,
|
||||||
|
single_qa_group_size: 0,
|
||||||
|
multiple_qa_group_size: 0,
|
||||||
|
new_qa_group_size: 0,
|
||||||
|
new_single_qa_group_size: 0,
|
||||||
|
new_multiple_qa_group_size: 0,
|
||||||
|
review_question_size: 0,
|
||||||
|
comment_question_size: 0,
|
||||||
|
})
|
||||||
|
|
||||||
export interface selectedDataProps {
|
export interface selectedDataProps {
|
||||||
status: number
|
status: number
|
||||||
uid: number | null
|
uid: number | null
|
||||||
@@ -195,6 +220,7 @@ export default function TaskTableContainer(props: {
|
|||||||
const { setBackProps } = useBackUrlStore()
|
const { setBackProps } = useBackUrlStore()
|
||||||
|
|
||||||
const [total, setTotal] = useState(0)
|
const [total, setTotal] = useState(0)
|
||||||
|
const [totalSize, setTotalSize] = useState<Task.SizeProps>(EMPTY_TASK_SIZE)
|
||||||
|
|
||||||
const [pageNumber, setPageNumber] = useState(1)
|
const [pageNumber, setPageNumber] = useState(1)
|
||||||
const [pageSize, setPageSize] = useState(15)
|
const [pageSize, setPageSize] = useState(15)
|
||||||
@@ -324,9 +350,11 @@ export default function TaskTableContainer(props: {
|
|||||||
const res = await getTaskList(appliedParams)
|
const res = await getTaskList(appliedParams)
|
||||||
setRecords(res?.task_list ?? [])
|
setRecords(res?.task_list ?? [])
|
||||||
setTotal(res?.total_items ?? 0)
|
setTotal(res?.total_items ?? 0)
|
||||||
|
setTotalSize(res?.total_size ?? EMPTY_TASK_SIZE)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setRecords([])
|
setRecords([])
|
||||||
setTotal(0)
|
setTotal(0)
|
||||||
|
setTotalSize(EMPTY_TASK_SIZE)
|
||||||
notifications.show({
|
notifications.show({
|
||||||
color: "red",
|
color: "red",
|
||||||
title: "加载失败",
|
title: "加载失败",
|
||||||
@@ -621,6 +649,7 @@ export default function TaskTableContainer(props: {
|
|||||||
width,
|
width,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
render: (record) => record.label_object_size?.[accessor] ?? "-",
|
render: (record) => record.label_object_size?.[accessor] ?? "-",
|
||||||
|
footer: totalSize[accessor] ?? 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
const cols: DataTableColumn<Task.DataProps>[] = [
|
const cols: DataTableColumn<Task.DataProps>[] = [
|
||||||
@@ -628,6 +657,7 @@ export default function TaskTableContainer(props: {
|
|||||||
accessor: "id",
|
accessor: "id",
|
||||||
title: "任务ID",
|
title: "任务ID",
|
||||||
width: 90,
|
width: 90,
|
||||||
|
footer: "总计",
|
||||||
render: (record) => (
|
render: (record) => (
|
||||||
<Button
|
<Button
|
||||||
variant="transparent"
|
variant="transparent"
|
||||||
@@ -805,7 +835,15 @@ export default function TaskTableContainer(props: {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
return cols
|
return cols
|
||||||
}, [hasRolePermissions, info, projectId, router, setBackProps, type])
|
}, [
|
||||||
|
hasRolePermissions,
|
||||||
|
info,
|
||||||
|
projectId,
|
||||||
|
router,
|
||||||
|
setBackProps,
|
||||||
|
totalSize,
|
||||||
|
type,
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -307,6 +307,7 @@ const LabelPage = ({
|
|||||||
activeOperation,
|
activeOperation,
|
||||||
setActiveOperation,
|
setActiveOperation,
|
||||||
setDrawOption,
|
setDrawOption,
|
||||||
|
setSubAttrPresetShow,
|
||||||
showObjectList,
|
showObjectList,
|
||||||
showGroupList,
|
showGroupList,
|
||||||
showTaskList,
|
showTaskList,
|
||||||
@@ -1433,6 +1434,31 @@ const LabelPage = ({
|
|||||||
|
|
||||||
const { setShift, focusInput } = useKeyEventStore()
|
const { setShift, focusInput } = useKeyEventStore()
|
||||||
const drawAction = useKeyboardStore((state) => state.drawAction)
|
const drawAction = useKeyboardStore((state) => state.drawAction)
|
||||||
|
const initializedDrawActionTaskIdRef = useRef<number | null>(null)
|
||||||
|
|
||||||
|
const handleSelectOperation = useCallback(
|
||||||
|
(operationId: string) => {
|
||||||
|
const operationSchema = getOperationSchema(operationId)
|
||||||
|
if (!operationSchema) return false
|
||||||
|
|
||||||
|
setActiveOperation(operationId)
|
||||||
|
setSubAttrPresetShow(!!operationSchema.sub_attributes_describe?.length)
|
||||||
|
|
||||||
|
if (isLabelTask) {
|
||||||
|
setEditMode(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
[
|
||||||
|
getOperationSchema,
|
||||||
|
isLabelTask,
|
||||||
|
setActiveOperation,
|
||||||
|
setEditMode,
|
||||||
|
setSubAttrPresetShow,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
const drawShortcutSnapshotRef = useRef<{
|
const drawShortcutSnapshotRef = useRef<{
|
||||||
activeOperation: string
|
activeOperation: string
|
||||||
drawOption: "default" | "intersect" | "unite"
|
drawOption: "default" | "intersect" | "unite"
|
||||||
@@ -1441,20 +1467,17 @@ const LabelPage = ({
|
|||||||
|
|
||||||
const handleShortcut = useCallback(
|
const handleShortcut = useCallback(
|
||||||
(key: string, ctrl: boolean) => {
|
(key: string, ctrl: boolean) => {
|
||||||
let checkOperation = getOperationSchema(key)
|
|
||||||
const mode = usePaperStore.getState().mode
|
const mode = usePaperStore.getState().mode
|
||||||
|
const nextOperationId = ctrl ? (+key + 10).toString() : key
|
||||||
|
const checkOperation = getOperationSchema(nextOperationId)
|
||||||
// 标注方案里面存在的非文本类型标注才能切换
|
// 标注方案里面存在的非文本类型标注才能切换
|
||||||
if (checkOperation) {
|
if (checkOperation) {
|
||||||
// 辅助标注模式下非多边形类型不能切换
|
// 辅助标注模式下非多边形类型不能切换
|
||||||
if (mode === "support" && checkOperation.label_type !== 102) return
|
if (mode === "support" && checkOperation.label_type !== 102) return
|
||||||
if (ctrl) {
|
handleSelectOperation(nextOperationId)
|
||||||
setActiveOperation((+key + 10).toString())
|
|
||||||
} else {
|
|
||||||
setActiveOperation(key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[getOperationSchema, setActiveOperation]
|
[getOperationSchema, handleSelectOperation]
|
||||||
)
|
)
|
||||||
|
|
||||||
const resolveSelectedObjectContext = useCallback(() => {
|
const resolveSelectedObjectContext = useCallback(() => {
|
||||||
@@ -1594,6 +1617,50 @@ const LabelPage = ({
|
|||||||
})
|
})
|
||||||
}, [activeImage, labelData])
|
}, [activeImage, labelData])
|
||||||
|
|
||||||
|
const handleToggleHideSelectionOrAll = useCallback(() => {
|
||||||
|
const selectedIds =
|
||||||
|
useObjectStore.getState().selectedPath[activeImage] || []
|
||||||
|
if (!selectedIds.length) {
|
||||||
|
handleToggleHideAllObjects()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeImageLabel = labelData.get(activeImage)
|
||||||
|
if (!activeImageLabel?.size) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedIdSet = new Set(selectedIds)
|
||||||
|
const selectedObjects: Array<{
|
||||||
|
operationId: string
|
||||||
|
objectId: number
|
||||||
|
}> = []
|
||||||
|
|
||||||
|
activeImageLabel.forEach((paths, operationId) => {
|
||||||
|
paths.forEach(([objectId]) => {
|
||||||
|
if (!selectedIdSet.has(objectId)) return
|
||||||
|
selectedObjects.push({
|
||||||
|
operationId,
|
||||||
|
objectId,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!selectedObjects.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { pathStatus } = useObjectStore.getState()
|
||||||
|
const areAllSelectedObjectsHidden = selectedObjects.every(
|
||||||
|
({ objectId }) => pathStatus[activeImage + objectId]?.HIDE ?? false
|
||||||
|
)
|
||||||
|
const nextHide = !areAllSelectedObjectsHidden
|
||||||
|
|
||||||
|
selectedObjects.forEach(({ operationId, objectId }) => {
|
||||||
|
toggleObjectHideByShortcut(activeImage, operationId, objectId, nextHide)
|
||||||
|
})
|
||||||
|
}, [activeImage, handleToggleHideAllObjects, labelData])
|
||||||
|
|
||||||
const rerenderActiveImageByLabel = useCallback(
|
const rerenderActiveImageByLabel = useCallback(
|
||||||
(
|
(
|
||||||
imageId: string,
|
imageId: string,
|
||||||
@@ -2185,7 +2252,7 @@ const LabelPage = ({
|
|||||||
|
|
||||||
if (!e.ctrlKey && !e.metaKey && !e.altKey && lowerKey === "h") {
|
if (!e.ctrlKey && !e.metaKey && !e.altKey && lowerKey === "h") {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
handleToggleHideAllObjects()
|
handleToggleHideSelectionOrAll()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2487,6 +2554,7 @@ const LabelPage = ({
|
|||||||
focusInput,
|
focusInput,
|
||||||
getOperationSchema,
|
getOperationSchema,
|
||||||
handleToggleHideAllObjects,
|
handleToggleHideAllObjects,
|
||||||
|
handleToggleHideSelectionOrAll,
|
||||||
handleMergeSelectedObjects,
|
handleMergeSelectedObjects,
|
||||||
handleContinueSelectedPolygon,
|
handleContinueSelectedPolygon,
|
||||||
handleShortcut,
|
handleShortcut,
|
||||||
@@ -2519,6 +2587,14 @@ const LabelPage = ({
|
|||||||
drawShortcutSnapshotRef.current = null
|
drawShortcutSnapshotRef.current = null
|
||||||
}, [activeImage])
|
}, [activeImage])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!taskDetail?.id || !activeImage || !isLabelTask) return
|
||||||
|
if (initializedDrawActionTaskIdRef.current === taskDetail.id) return
|
||||||
|
|
||||||
|
useKeyboardStore.getState().setDrawAction("subtract")
|
||||||
|
initializedDrawActionTaskIdRef.current = taskDetail.id
|
||||||
|
}, [activeImage, isLabelTask, taskDetail?.id])
|
||||||
|
|
||||||
const handleBeforeUnload = (e: any) => {
|
const handleBeforeUnload = (e: any) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
// 备份
|
// 备份
|
||||||
@@ -2708,6 +2784,7 @@ const LabelPage = ({
|
|||||||
oldWorkLoad={oldWorkLoad}
|
oldWorkLoad={oldWorkLoad}
|
||||||
updateOldWorkLoad={updateOldWorkLoad}
|
updateOldWorkLoad={updateOldWorkLoad}
|
||||||
isLabelTask={isLabelTask}
|
isLabelTask={isLabelTask}
|
||||||
|
onOperationChange={handleSelectOperation}
|
||||||
renderPolygons={
|
renderPolygons={
|
||||||
paperContainerRef.current
|
paperContainerRef.current
|
||||||
? paperContainerRef.current.renderPolygons
|
? paperContainerRef.current.renderPolygons
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import { Box } from "@mantine/core"
|
import { Box } from "@mantine/core"
|
||||||
import { RichTextEditor } from "@mantine/tiptap"
|
import { RichTextEditor } from "@mantine/tiptap"
|
||||||
import "@mantine/tiptap/styles.css"
|
import "@mantine/tiptap/styles.css"
|
||||||
import { IconPhoto } from "@tabler/icons-react"
|
|
||||||
import Image from "@tiptap/extension-image"
|
import Image from "@tiptap/extension-image"
|
||||||
import Link from "@tiptap/extension-link"
|
import Link from "@tiptap/extension-link"
|
||||||
import Placeholder from "@tiptap/extension-placeholder"
|
import Placeholder from "@tiptap/extension-placeholder"
|
||||||
@@ -148,7 +147,7 @@ const EditorContainer = ({
|
|||||||
<RichTextEditor.Hr />
|
<RichTextEditor.Hr />
|
||||||
</RichTextEditor.ControlsGroup>
|
</RichTextEditor.ControlsGroup>
|
||||||
|
|
||||||
<RichTextEditor.ControlsGroup>
|
{/* <RichTextEditor.ControlsGroup>
|
||||||
<RichTextEditor.Link />
|
<RichTextEditor.Link />
|
||||||
<RichTextEditor.Unlink />
|
<RichTextEditor.Unlink />
|
||||||
</RichTextEditor.ControlsGroup>
|
</RichTextEditor.ControlsGroup>
|
||||||
@@ -160,7 +159,7 @@ const EditorContainer = ({
|
|||||||
title="上传图片">
|
title="上传图片">
|
||||||
<IconPhoto stroke={1.5} size="1rem" />
|
<IconPhoto stroke={1.5} size="1rem" />
|
||||||
</RichTextEditor.Control>
|
</RichTextEditor.Control>
|
||||||
</RichTextEditor.ControlsGroup>
|
</RichTextEditor.ControlsGroup> */}
|
||||||
</RichTextEditor.Toolbar>
|
</RichTextEditor.Toolbar>
|
||||||
|
|
||||||
<RichTextEditor.Content h={144} style={{ overflowY: "auto" }} />
|
<RichTextEditor.Content h={144} style={{ overflowY: "auto" }} />
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ import { renderGroupPath } from "../useRenderGroupPath"
|
|||||||
import useRenderTag from "../useRenderTag"
|
import useRenderTag from "../useRenderTag"
|
||||||
import { useRightToolsStore } from "../useRightToolsStore"
|
import { useRightToolsStore } from "../useRightToolsStore"
|
||||||
import { useTopToolsStore } from "../useTopToolsStore"
|
import { useTopToolsStore } from "../useTopToolsStore"
|
||||||
import { checkCommentsIsSame } from "../util"
|
import { buildSubAttributeFormValues, checkCommentsIsSame } from "../util"
|
||||||
import { safeClone } from "../utils/clone"
|
import { safeClone } from "../utils/clone"
|
||||||
import { labelTypeMap } from "../utils/constants"
|
import { labelTypeMap } from "../utils/constants"
|
||||||
import { adjustPoints } from "../utils/paperjs"
|
import { adjustPoints } from "../utils/paperjs"
|
||||||
@@ -3315,50 +3315,26 @@ const PaperContainer = (
|
|||||||
.get(activeImage)
|
.get(activeImage)
|
||||||
?.get(operationId)
|
?.get(operationId)
|
||||||
?.find((item) => item[0] === id)
|
?.find((item) => item[0] === id)
|
||||||
|
const operationSchema = getOperationSchema(operationId)
|
||||||
form.setFieldValue("id", id.toString())
|
|
||||||
form.setFieldValue("operation", operationId)
|
|
||||||
if (currentPath?.[2].sub_attributes) {
|
|
||||||
let operationSchema = getOperationSchema(operationId)
|
|
||||||
let obj: {
|
|
||||||
[key: string]: string | string[]
|
|
||||||
} = {}
|
|
||||||
Object.entries(currentPath?.[2].sub_attributes).map(([key, value]) => {
|
|
||||||
let select_mode = operationSchema?.sub_attributes_describe?.find(
|
|
||||||
(item) => item.chinese_name === key
|
|
||||||
)?.select_mode
|
|
||||||
switch (select_mode) {
|
|
||||||
case 2:
|
|
||||||
obj[key] = Array.isArray(value)
|
|
||||||
? value
|
|
||||||
: (value as string)
|
|
||||||
.split(",")
|
|
||||||
.map((item) => item.trim())
|
|
||||||
.filter(Boolean)
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
obj[key] = value as string
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
form.setFieldValue("sub_attributes", obj)
|
|
||||||
}
|
|
||||||
if (currentPath?.[2].comment) {
|
|
||||||
const nowComment =
|
const nowComment =
|
||||||
currentPath?.[2].comment[currentPath?.[2].comment.length - 1]
|
currentPath?.[2].comment?.[currentPath?.[2].comment.length - 1]
|
||||||
form.setFieldValue(
|
|
||||||
"check_box_comments",
|
form.setValues({
|
||||||
|
id: id.toString(),
|
||||||
|
operation: operationId,
|
||||||
|
sub_attributes: buildSubAttributeFormValues(
|
||||||
|
operationSchema,
|
||||||
|
currentPath?.[2].sub_attributes || {}
|
||||||
|
),
|
||||||
|
check_box_comments:
|
||||||
nowComment && nowComment.check_box_comments.length
|
nowComment && nowComment.check_box_comments.length
|
||||||
? nowComment.check_box_comments
|
? nowComment.check_box_comments
|
||||||
: []
|
: [],
|
||||||
)
|
text_comments:
|
||||||
form.setFieldValue(
|
|
||||||
"text_comments",
|
|
||||||
nowComment && nowComment.text_comments.length
|
nowComment && nowComment.text_comments.length
|
||||||
? nowComment.text_comments[0]
|
? nowComment.text_comments[0]
|
||||||
: ""
|
: "",
|
||||||
)
|
})
|
||||||
}
|
|
||||||
// 可选的ids
|
// 可选的ids
|
||||||
let images = Array.from(labelState.keys()).filter(
|
let images = Array.from(labelState.keys()).filter(
|
||||||
(key) => key !== activeImage
|
(key) => key !== activeImage
|
||||||
@@ -3580,11 +3556,10 @@ const PaperContainer = (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// newOperation的subAttributes
|
// newOperation的subAttributes
|
||||||
let subAttr = Object.assign(
|
let subAttr = safeClone(
|
||||||
{},
|
|
||||||
useTopToolsStore.getState().subAttributes[
|
useTopToolsStore.getState().subAttributes[
|
||||||
operationSchema?.label_class ?? ""
|
operationSchema?.label_class ?? ""
|
||||||
]
|
] || {}
|
||||||
)
|
)
|
||||||
// 修改labeldata
|
// 修改labeldata
|
||||||
setOperation(activeImage, newOperation, [
|
setOperation(activeImage, newOperation, [
|
||||||
@@ -3612,16 +3587,21 @@ const PaperContainer = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const handleChangeContextMenuSubAttr = useCallback(
|
const handleChangeContextMenuSubAttr = useCallback(
|
||||||
(key: string, value: string) => {
|
(key: string, value: string | string[]) => {
|
||||||
|
const currentSubAttributes = safeClone(
|
||||||
|
(pathItem?.[2]?.sub_attributes ||
|
||||||
|
newDetail.sub_attributes ||
|
||||||
|
{}) as Record<string, any>
|
||||||
|
)
|
||||||
|
currentSubAttributes[key] = Array.isArray(value) ? value.join(",") : value
|
||||||
|
|
||||||
setOperation(activeImage, operationId, [
|
setOperation(activeImage, operationId, [
|
||||||
id,
|
id,
|
||||||
pathItem?.[1] || [],
|
pathItem?.[1] || [],
|
||||||
{
|
{
|
||||||
...newDetail,
|
...newDetail,
|
||||||
...(pathItem?.[2] || {}),
|
...(pathItem?.[2] || {}),
|
||||||
sub_attributes: Object.assign(newDetail.sub_attributes || {}, {
|
sub_attributes: currentSubAttributes,
|
||||||
[key]: value,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
pathItem?.[3] || [],
|
pathItem?.[3] || [],
|
||||||
])
|
])
|
||||||
@@ -3892,7 +3872,7 @@ const PaperContainer = (
|
|||||||
)
|
)
|
||||||
handleChangeContextMenuSubAttr(
|
handleChangeContextMenuSubAttr(
|
||||||
item.chinese_name,
|
item.chinese_name,
|
||||||
value.toString()
|
value
|
||||||
)
|
)
|
||||||
}}>
|
}}>
|
||||||
<Stack gap={6} mt={6}>
|
<Stack gap={6} mt={6}>
|
||||||
|
|||||||
@@ -166,6 +166,24 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
[activeImage, continueObjectId, storeLabel]
|
[activeImage, continueObjectId, storeLabel]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const getObjectItemsById = useCallback(
|
||||||
|
(id: number) => {
|
||||||
|
return getItemsById(id).filter((item) => item.data?.type !== "tag")
|
||||||
|
},
|
||||||
|
[getItemsById]
|
||||||
|
)
|
||||||
|
|
||||||
|
const bringTagItemsToFront = useCallback(
|
||||||
|
(id: number) => {
|
||||||
|
getItemsById(id).forEach((item) => {
|
||||||
|
if (item.data?.type === "tag") {
|
||||||
|
item.bringToFront()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[getItemsById]
|
||||||
|
)
|
||||||
|
|
||||||
// 切换选中对象时,清除所有其他对象的当前选中状态
|
// 切换选中对象时,清除所有其他对象的当前选中状态
|
||||||
const clearSelectedItems = () => {
|
const clearSelectedItems = () => {
|
||||||
usePaperStore
|
usePaperStore
|
||||||
@@ -215,11 +233,16 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
|
|
||||||
const handleSelect = useCallback(
|
const handleSelect = useCallback(
|
||||||
(id: number, operationId: any) => {
|
(id: number, operationId: any) => {
|
||||||
|
if (pathStatus[activeImage + id]?.HIDE) return
|
||||||
|
|
||||||
|
const objectItems = getObjectItemsById(id)
|
||||||
|
const targetItem = getItemById(id)
|
||||||
|
|
||||||
if (selectedPath[activeImage]?.length) {
|
if (selectedPath[activeImage]?.length) {
|
||||||
if (!selectedPath[activeImage]?.includes(id)) {
|
if (!selectedPath[activeImage]?.includes(id)) {
|
||||||
if (pressShift) {
|
if (pressShift) {
|
||||||
if (getItemsById(id)?.length) {
|
if (objectItems.length && targetItem) {
|
||||||
getItemsById(id).forEach((item) => {
|
objectItems.forEach((item) => {
|
||||||
if (item instanceof paper.Path) {
|
if (item instanceof paper.Path) {
|
||||||
handleSelectedPath(item)
|
handleSelectedPath(item)
|
||||||
} else if (item instanceof paper.CompoundPath) {
|
} else if (item instanceof paper.CompoundPath) {
|
||||||
@@ -228,13 +251,14 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
else item.data.selected = true
|
else item.data.selected = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
bringTagItemsToFront(id)
|
||||||
let category = useTopToolsStore
|
let category = useTopToolsStore
|
||||||
.getState()
|
.getState()
|
||||||
.objectOperations.find(
|
.objectOperations.find(
|
||||||
(item) => item.category_id.toString() === operationId
|
(item) => item.category_id.toString() === operationId
|
||||||
)
|
)
|
||||||
const globalPosition = getItemById(id)!.globalMatrix.transform(
|
const globalPosition = targetItem.globalMatrix.transform(
|
||||||
getItemById(id)!.position
|
targetItem.position
|
||||||
)
|
)
|
||||||
const { top, left } = getShowContextMenuPosition(
|
const { top, left } = getShowContextMenuPosition(
|
||||||
globalPosition,
|
globalPosition,
|
||||||
@@ -251,8 +275,9 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
clearSelectedItems()
|
clearSelectedItems()
|
||||||
selectedPath[activeImage].forEach((selectedId) => {
|
selectedPath[activeImage].forEach((selectedId) => {
|
||||||
if (getItemsById(selectedId)?.length) {
|
const selectedObjectItems = getObjectItemsById(selectedId)
|
||||||
getItemsById(selectedId).forEach((item) => {
|
if (selectedObjectItems.length) {
|
||||||
|
selectedObjectItems.forEach((item) => {
|
||||||
cancelSelectedPathColor(item)
|
cancelSelectedPathColor(item)
|
||||||
})
|
})
|
||||||
useOtherToolsStore.getState().setShowContextMenu({
|
useOtherToolsStore.getState().setShowContextMenu({
|
||||||
@@ -267,8 +292,8 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (getItemsById(id)?.length) {
|
if (objectItems.length && targetItem) {
|
||||||
getItemsById(id).forEach((item) => {
|
objectItems.forEach((item) => {
|
||||||
if (item instanceof paper.Path) {
|
if (item instanceof paper.Path) {
|
||||||
handleSelectedPath(item)
|
handleSelectedPath(item)
|
||||||
} else if (item instanceof paper.CompoundPath) {
|
} else if (item instanceof paper.CompoundPath) {
|
||||||
@@ -277,13 +302,14 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
else item.data.selected = true
|
else item.data.selected = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
bringTagItemsToFront(id)
|
||||||
let category = useTopToolsStore
|
let category = useTopToolsStore
|
||||||
.getState()
|
.getState()
|
||||||
.objectOperations.find(
|
.objectOperations.find(
|
||||||
(item) => item.category_id.toString() === operationId
|
(item) => item.category_id.toString() === operationId
|
||||||
)
|
)
|
||||||
const globalPosition = getItemById(id)!.globalMatrix.transform(
|
const globalPosition = targetItem.globalMatrix.transform(
|
||||||
getItemById(id)!.position
|
targetItem.position
|
||||||
)
|
)
|
||||||
const { top, left } = getShowContextMenuPosition(
|
const { top, left } = getShowContextMenuPosition(
|
||||||
globalPosition,
|
globalPosition,
|
||||||
@@ -302,8 +328,8 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
clearSelectedItems()
|
clearSelectedItems()
|
||||||
updateSelectedPath(activeImage, "DELETE", id)
|
updateSelectedPath(activeImage, "DELETE", id)
|
||||||
if (getItemsById(id)?.length) {
|
if (objectItems.length) {
|
||||||
getItemsById(id).forEach((item) => {
|
objectItems.forEach((item) => {
|
||||||
cancelSelectedPathColor(item)
|
cancelSelectedPathColor(item)
|
||||||
})
|
})
|
||||||
useOtherToolsStore.getState().setShowContextMenu({
|
useOtherToolsStore.getState().setShowContextMenu({
|
||||||
@@ -321,8 +347,8 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
clearSelectedItems()
|
clearSelectedItems()
|
||||||
updateSelectedPath(activeImage, "ADD", id)
|
updateSelectedPath(activeImage, "ADD", id)
|
||||||
if (getItemsById(id)?.length) {
|
if (objectItems.length && targetItem) {
|
||||||
getItemsById(id).forEach((item) => {
|
objectItems.forEach((item) => {
|
||||||
if (item instanceof paper.Path) {
|
if (item instanceof paper.Path) {
|
||||||
handleSelectedPath(item)
|
handleSelectedPath(item)
|
||||||
} else if (item instanceof paper.CompoundPath) {
|
} else if (item instanceof paper.CompoundPath) {
|
||||||
@@ -337,14 +363,15 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
// item.fillColor = item.data?.fillColor;
|
// item.fillColor = item.data?.fillColor;
|
||||||
// item.bringToFront();
|
// item.bringToFront();
|
||||||
})
|
})
|
||||||
|
bringTagItemsToFront(id)
|
||||||
|
|
||||||
let category = useTopToolsStore
|
let category = useTopToolsStore
|
||||||
.getState()
|
.getState()
|
||||||
.objectOperations.find(
|
.objectOperations.find(
|
||||||
(item) => item.category_id.toString() === operationId
|
(item) => item.category_id.toString() === operationId
|
||||||
)
|
)
|
||||||
const globalPosition = getItemById(id)!.globalMatrix.transform(
|
const globalPosition = targetItem.globalMatrix.transform(
|
||||||
getItemById(id)!.position
|
targetItem.position
|
||||||
)
|
)
|
||||||
const { top, left } = getShowContextMenuPosition(
|
const { top, left } = getShowContextMenuPosition(
|
||||||
globalPosition,
|
globalPosition,
|
||||||
@@ -362,8 +389,10 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
activeImage,
|
activeImage,
|
||||||
|
bringTagItemsToFront,
|
||||||
|
getObjectItemsById,
|
||||||
getItemById,
|
getItemById,
|
||||||
getItemsById,
|
pathStatus,
|
||||||
pressShift,
|
pressShift,
|
||||||
selectedPath,
|
selectedPath,
|
||||||
updateSelectedPath,
|
updateSelectedPath,
|
||||||
@@ -889,10 +918,13 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
|||||||
: "var(--mantine-color-gray-0)"
|
: "var(--mantine-color-gray-0)"
|
||||||
}
|
}
|
||||||
c={isSelected ? "white" : undefined}
|
c={isSelected ? "white" : undefined}
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
|
if (isChildHide) return
|
||||||
handleSelect(child[0], operationId)
|
handleSelect(child[0], operationId)
|
||||||
}
|
}}
|
||||||
style={{ cursor: "pointer" }}>
|
style={{
|
||||||
|
cursor: isChildHide ? "default" : "pointer",
|
||||||
|
}}>
|
||||||
<Flex justify="space-between" align="center">
|
<Flex justify="space-between" align="center">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ import {
|
|||||||
NODE_SIZE_MIN,
|
NODE_SIZE_MIN,
|
||||||
useTopToolsStore,
|
useTopToolsStore,
|
||||||
} from "../useTopToolsStore"
|
} from "../useTopToolsStore"
|
||||||
import { getSubAttrStatus } from "../util"
|
import { buildSubAttributeFormValues, 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"
|
||||||
import { adjustAllPoints } from "../utils/paperjs"
|
import { adjustAllPoints } from "../utils/paperjs"
|
||||||
@@ -118,6 +118,7 @@ interface TopToolsComponentProps {
|
|||||||
oldWorkLoad: WorkLoad | null
|
oldWorkLoad: WorkLoad | null
|
||||||
updateOldWorkLoad: (data: WorkLoad) => void
|
updateOldWorkLoad: (data: WorkLoad) => void
|
||||||
isLabelTask: boolean
|
isLabelTask: boolean
|
||||||
|
onOperationChange: (operationId: string) => void
|
||||||
renderPolygons: (
|
renderPolygons: (
|
||||||
operationId: string,
|
operationId: string,
|
||||||
imageData: Map<string, [number, any[], any, any[]][]> | undefined
|
imageData: Map<string, [number, any[], any, any[]][]> | undefined
|
||||||
@@ -161,6 +162,7 @@ const TopTools = (
|
|||||||
oldWorkLoad,
|
oldWorkLoad,
|
||||||
updateOldWorkLoad,
|
updateOldWorkLoad,
|
||||||
isLabelTask,
|
isLabelTask,
|
||||||
|
onOperationChange,
|
||||||
renderPolygons,
|
renderPolygons,
|
||||||
} = props
|
} = props
|
||||||
const { backUrl, basePath } = useBackUrlStore()
|
const { backUrl, basePath } = useBackUrlStore()
|
||||||
@@ -1488,36 +1490,10 @@ const TopTools = (
|
|||||||
operationId: string,
|
operationId: string,
|
||||||
values: Record<string, string | string[] | undefined> = {}
|
values: Record<string, string | string[] | undefined> = {}
|
||||||
) => {
|
) => {
|
||||||
const schema = getOperationSchema(operationId)
|
return buildSubAttributeFormValues(
|
||||||
if (!schema?.sub_attributes_describe?.length) return {}
|
getOperationSchema(operationId),
|
||||||
|
values
|
||||||
const nextValues: Record<string, string | string[]> = {}
|
|
||||||
|
|
||||||
schema.sub_attributes_describe.forEach((item) => {
|
|
||||||
const currentValue = values[item.chinese_name]
|
|
||||||
if (
|
|
||||||
currentValue === undefined ||
|
|
||||||
currentValue === null ||
|
|
||||||
currentValue === ""
|
|
||||||
)
|
)
|
||||||
return
|
|
||||||
|
|
||||||
if (item.select_mode === 2) {
|
|
||||||
nextValues[item.chinese_name] = Array.isArray(currentValue)
|
|
||||||
? currentValue
|
|
||||||
: currentValue
|
|
||||||
.split(",")
|
|
||||||
.map((value) => value.trim())
|
|
||||||
.filter(Boolean)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
nextValues[item.chinese_name] = Array.isArray(currentValue)
|
|
||||||
? currentValue[0] || ""
|
|
||||||
: currentValue
|
|
||||||
})
|
|
||||||
|
|
||||||
return nextValues
|
|
||||||
},
|
},
|
||||||
[getOperationSchema]
|
[getOperationSchema]
|
||||||
)
|
)
|
||||||
@@ -1627,6 +1603,10 @@ const TopTools = (
|
|||||||
size="xs"
|
size="xs"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
form.reset()
|
form.reset()
|
||||||
|
form.setFieldValue(
|
||||||
|
"sub_attributes",
|
||||||
|
getPresetFormValues(activeOperation, {})
|
||||||
|
)
|
||||||
if (operationSchema?.label_class)
|
if (operationSchema?.label_class)
|
||||||
setsubAttributes(operationSchema.label_class, {})
|
setsubAttributes(operationSchema.label_class, {})
|
||||||
}}>
|
}}>
|
||||||
@@ -2334,7 +2314,7 @@ const TopTools = (
|
|||||||
<UnstyledButton
|
<UnstyledButton
|
||||||
key={item.category_id}
|
key={item.category_id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActiveOperation(item.category_id.toString())
|
onOperationChange(item.category_id.toString())
|
||||||
setOperationPickerOpened(false)
|
setOperationPickerOpened(false)
|
||||||
setOperationKeyword("")
|
setOperationKeyword("")
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { usePaperSupportStore } from "./usePaperSupportStore"
|
|||||||
import { useRightToolsStore } from "./useRightToolsStore"
|
import { useRightToolsStore } from "./useRightToolsStore"
|
||||||
import { DEFAULT_NODE_SIZE, useTopToolsStore } from "./useTopToolsStore"
|
import { DEFAULT_NODE_SIZE, useTopToolsStore } from "./useTopToolsStore"
|
||||||
import { safeClone } from "./utils/clone"
|
import { safeClone } from "./utils/clone"
|
||||||
|
import { getObjectTagVisibility } from "./utils/objectVisibility"
|
||||||
|
|
||||||
interface ContinuePolygonTarget {
|
interface ContinuePolygonTarget {
|
||||||
imageId: string
|
imageId: string
|
||||||
@@ -216,6 +217,16 @@ const initialPaperState = {
|
|||||||
reciprocalRasterScale: {},
|
reciprocalRasterScale: {},
|
||||||
resizeGhostRequestToken: 0,
|
resizeGhostRequestToken: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const insertItemBelowTags = (item: paper.Item | null | undefined) => {
|
||||||
|
if (!item) return
|
||||||
|
const group = usePaperStore.getState().group
|
||||||
|
if (!group || item.parent !== group) return
|
||||||
|
const firstTagItem = group.getItems({ data: { type: "tag" } })[0]
|
||||||
|
if (!firstTagItem || firstTagItem === item) return
|
||||||
|
item.insertBelow(firstTagItem)
|
||||||
|
}
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
const group = usePaperStore.getState().group!
|
const group = usePaperStore.getState().group!
|
||||||
const imageId = useBottomToolsStore.getState().activeImage
|
const imageId = useBottomToolsStore.getState().activeImage
|
||||||
@@ -450,12 +461,7 @@ const clearPaperSelectedObjects = () => {
|
|||||||
.getState()
|
.getState()
|
||||||
.getItemsById(id)
|
.getItemsById(id)
|
||||||
.forEach((item) => {
|
.forEach((item) => {
|
||||||
if (
|
resetPaperShapeFillColor(item)
|
||||||
(item instanceof paper.Path || item instanceof paper.CompoundPath) &&
|
|
||||||
["rectangle", "polygon"].includes(item.data?.type || "")
|
|
||||||
) {
|
|
||||||
item.fillColor = item.data?.blankColor || item.fillColor || null
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -464,6 +470,16 @@ const clearPaperSelectedObjects = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resetPaperShapeFillColor = (item: paper.Item) => {
|
||||||
|
if (!(item instanceof paper.Path || item instanceof paper.CompoundPath)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!["rectangle", "polygon"].includes(item.data?.type || "")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
item.fillColor = item.data?.blankColor || item.fillColor || null
|
||||||
|
}
|
||||||
|
|
||||||
const applyPaperSelectedPath = (item: paper.Path | paper.CompoundPath) => {
|
const applyPaperSelectedPath = (item: paper.Path | paper.CompoundPath) => {
|
||||||
if (item.data.type === "rectangle" && item instanceof paper.Path) {
|
if (item.data.type === "rectangle" && item instanceof paper.Path) {
|
||||||
item.data.selected = true
|
item.data.selected = true
|
||||||
@@ -2011,15 +2027,14 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
type: "tag",
|
type: "tag",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
// 标识位为true时:选中路径隐藏tags; 没选中显示tags
|
// 仅恢复当前应显示的标签,隐藏对象的标签保持不可见
|
||||||
const configs = useTopToolsStore.getState().showTagsConfigs
|
|
||||||
if (useTopToolsStore.getState().showTags) {
|
if (useTopToolsStore.getState().showTags) {
|
||||||
const setTagVisibleByConfig = (tag: any) => {
|
const setTagVisibleByConfig = (tag: any) => {
|
||||||
if (tag.data.tag_category === "mask")
|
tag.visible = getObjectTagVisibility(
|
||||||
tag.visible = configs.includes("外框")
|
useBottomToolsStore.getState().activeImage,
|
||||||
else if (tag.data.tag_category === "point_text")
|
Number(tag.data?.id),
|
||||||
tag.visible = configs.includes("点ID")
|
tag.data?.tag_category
|
||||||
else tag.visible = true
|
)
|
||||||
}
|
}
|
||||||
lastTags.forEach(setTagVisibleByConfig)
|
lastTags.forEach(setTagVisibleByConfig)
|
||||||
tags.forEach(setTagVisibleByConfig)
|
tags.forEach(setTagVisibleByConfig)
|
||||||
@@ -3147,6 +3162,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
polygon.data = Object.assign({ type: "polygon", ...option }, data)
|
polygon.data = Object.assign({ type: "polygon", ...option }, data)
|
||||||
|
insertItemBelowTags(polygon)
|
||||||
points?.forEach((point) => {
|
points?.forEach((point) => {
|
||||||
polygon.add(point)
|
polygon.add(point)
|
||||||
})
|
})
|
||||||
@@ -3219,6 +3235,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
compoundPath.data = Object.assign({ type: "polygon", ...option }, data)
|
compoundPath.data = Object.assign({ type: "polygon", ...option }, data)
|
||||||
|
insertItemBelowTags(compoundPath)
|
||||||
compoundPath.onMouseDown = (e: {
|
compoundPath.onMouseDown = (e: {
|
||||||
event: MouseEvent
|
event: MouseEvent
|
||||||
point: paper.Point
|
point: paper.Point
|
||||||
@@ -4606,8 +4623,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
.getState()
|
.getState()
|
||||||
.group!.getItems({})
|
.group!.getItems({})
|
||||||
.forEach((item) => {
|
.forEach((item) => {
|
||||||
// clear color
|
resetPaperShapeFillColor(item)
|
||||||
item.fillColor = item?.data?.blankColor
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4803,6 +4819,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
Object.assign(option, { strokeScaling: false })
|
Object.assign(option, { strokeScaling: false })
|
||||||
)
|
)
|
||||||
rect.data = Object.assign({ type: "rectangle", ...option }, data)
|
rect.data = Object.assign({ type: "rectangle", ...option }, data)
|
||||||
|
insertItemBelowTags(rect)
|
||||||
rect.onMouseEnter = (_e: paper.MouseEvent) => {
|
rect.onMouseEnter = (_e: paper.MouseEvent) => {
|
||||||
// if (usePaperStore.getState().mode === "pan") {
|
// if (usePaperStore.getState().mode === "pan") {
|
||||||
// e.target.strokeWidth += 2;
|
// e.target.strokeWidth += 2;
|
||||||
@@ -5045,6 +5062,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
brush.data = Object.assign({ type: "brush", ...option }, data)
|
brush.data = Object.assign({ type: "brush", ...option }, data)
|
||||||
|
insertItemBelowTags(brush)
|
||||||
// points?.forEach((point) => {
|
// points?.forEach((point) => {
|
||||||
// brush.add(point);
|
// brush.add(point);
|
||||||
// });
|
// });
|
||||||
@@ -5545,6 +5563,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)
|
||||||
|
insertItemBelowTags(myCircle)
|
||||||
syncPaperCircleDiameter(myCircle)
|
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) {
|
||||||
@@ -5614,6 +5633,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
myCircleLine.data = Object.assign({ type: "point", ...option }, data)
|
myCircleLine.data = Object.assign({ type: "point", ...option }, data)
|
||||||
|
insertItemBelowTags(myCircleLine)
|
||||||
return myCircleLine
|
return myCircleLine
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useLabelStore } from "./store"
|
|||||||
import { useBottomToolsStore } from "./useBottomToolsStore"
|
import { useBottomToolsStore } from "./useBottomToolsStore"
|
||||||
import { usePaperStore } from "./usePaperStore"
|
import { usePaperStore } from "./usePaperStore"
|
||||||
import { useTopToolsStore } from "./useTopToolsStore"
|
import { useTopToolsStore } from "./useTopToolsStore"
|
||||||
|
import { getObjectTagVisibility } from "./utils/objectVisibility"
|
||||||
|
|
||||||
const TAG_FONT_SIZE = 12
|
const TAG_FONT_SIZE = 12
|
||||||
const TAG_VERTICAL_GAP = 8
|
const TAG_VERTICAL_GAP = 8
|
||||||
@@ -159,13 +160,12 @@ const useRenderTag = () => {
|
|||||||
const activeImage = useBottomToolsStore.getState().activeImage
|
const activeImage = useBottomToolsStore.getState().activeImage
|
||||||
const group = usePaperStore.getState().group
|
const group = usePaperStore.getState().group
|
||||||
if (!group) return
|
if (!group) return
|
||||||
const visible = useTopToolsStore.getState().showTags
|
|
||||||
const configs = useTopToolsStore.getState().showTagsConfigs
|
const configs = useTopToolsStore.getState().showTagsConfigs
|
||||||
const groupScale =
|
const groupScale =
|
||||||
Number.isFinite(group.scaling?.x) && group.scaling.x !== 0
|
Number.isFinite(group.scaling?.x) && group.scaling.x !== 0
|
||||||
? group.scaling.x
|
? group.scaling.x
|
||||||
: 1
|
: 1
|
||||||
const applyPointTagCompensation = (
|
const applyScreenSpaceTagCompensation = (
|
||||||
item: paper.Item,
|
item: paper.Item,
|
||||||
anchor: [number, number]
|
anchor: [number, number]
|
||||||
) => {
|
) => {
|
||||||
@@ -235,7 +235,7 @@ const useRenderTag = () => {
|
|||||||
tag_anchor: tagAnchor,
|
tag_anchor: tagAnchor,
|
||||||
},
|
},
|
||||||
parent: group,
|
parent: group,
|
||||||
visible,
|
visible: getObjectTagVisibility(activeImage, id, "text"),
|
||||||
})
|
})
|
||||||
text.translate(
|
text.translate(
|
||||||
new paper.Point(
|
new paper.Point(
|
||||||
@@ -259,8 +259,10 @@ const useRenderTag = () => {
|
|||||||
tag_anchor: tagAnchor,
|
tag_anchor: tagAnchor,
|
||||||
},
|
},
|
||||||
parent: group,
|
parent: group,
|
||||||
visible,
|
visible: getObjectTagVisibility(activeImage, id, "text_mask"),
|
||||||
})
|
})
|
||||||
|
applyScreenSpaceTagCompensation(text, tagAnchor)
|
||||||
|
applyScreenSpaceTagCompensation(textMask, tagAnchor)
|
||||||
text.bringToFront()
|
text.bringToFront()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +278,7 @@ const useRenderTag = () => {
|
|||||||
tag_category: "mask",
|
tag_category: "mask",
|
||||||
},
|
},
|
||||||
parent: group,
|
parent: group,
|
||||||
visible: visible && configs.includes("外框"),
|
visible: getObjectTagVisibility(activeImage, id, "mask"),
|
||||||
})
|
})
|
||||||
// 标注对象点id
|
// 标注对象点id
|
||||||
if (path instanceof paper.CompoundPath) {
|
if (path instanceof paper.CompoundPath) {
|
||||||
@@ -301,9 +303,9 @@ const useRenderTag = () => {
|
|||||||
tag_anchor: pointTextPosition,
|
tag_anchor: pointTextPosition,
|
||||||
},
|
},
|
||||||
parent: group,
|
parent: group,
|
||||||
visible: visible && configs.includes("点ID"),
|
visible: getObjectTagVisibility(activeImage, id, "point_text"),
|
||||||
})
|
})
|
||||||
applyPointTagCompensation(pointText, pointTextPosition)
|
applyScreenSpaceTagCompensation(pointText, pointTextPosition)
|
||||||
index++
|
index++
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -327,9 +329,9 @@ const useRenderTag = () => {
|
|||||||
tag_anchor: pointTextPosition,
|
tag_anchor: pointTextPosition,
|
||||||
},
|
},
|
||||||
parent: group,
|
parent: group,
|
||||||
visible: visible && configs.includes("点ID"),
|
visible: getObjectTagVisibility(activeImage, id, "point_text"),
|
||||||
})
|
})
|
||||||
applyPointTagCompensation(pointText, pointTextPosition)
|
applyScreenSpaceTagCompensation(pointText, pointTextPosition)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -86,6 +86,45 @@ export const getSubAttrStatus = (
|
|||||||
return bool
|
return bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const buildSubAttributeFormValues = (
|
||||||
|
operationSchema: Project.LabelSchemaList | null,
|
||||||
|
detail: Record<string, any> = {}
|
||||||
|
) => {
|
||||||
|
const nextValues: Record<string, string | string[]> = {}
|
||||||
|
if (!operationSchema?.sub_attributes_describe?.length) return nextValues
|
||||||
|
|
||||||
|
operationSchema.sub_attributes_describe.forEach((item) => {
|
||||||
|
nextValues[item.chinese_name] = item.select_mode === 2 ? [] : ""
|
||||||
|
|
||||||
|
const currentValue = detail?.[item.chinese_name]
|
||||||
|
if (
|
||||||
|
currentValue === undefined ||
|
||||||
|
currentValue === null ||
|
||||||
|
currentValue === "" ||
|
||||||
|
(Array.isArray(currentValue) && currentValue.length === 0)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.select_mode === 2) {
|
||||||
|
nextValues[item.chinese_name] = Array.isArray(currentValue)
|
||||||
|
? currentValue
|
||||||
|
: currentValue
|
||||||
|
.toString()
|
||||||
|
.split(",")
|
||||||
|
.map((value: string) => value.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nextValues[item.chinese_name] = Array.isArray(currentValue)
|
||||||
|
? currentValue[0] || ""
|
||||||
|
: currentValue.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
return nextValues
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
export const checkCommentsIsSame: (
|
export const checkCommentsIsSame: (
|
||||||
a: any[] | null,
|
a: any[] | null,
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import paper from "paper"
|
import paper from "paper"
|
||||||
import { useLabelStore, useObjectStore } from "../store"
|
import { useLabelStore, useObjectStore } from "../store"
|
||||||
|
import { useOtherToolsStore } from "../useOtherToolsStore"
|
||||||
import { usePaperStore } from "../usePaperStore"
|
import { usePaperStore } from "../usePaperStore"
|
||||||
|
import { usePaperSupportStore } from "../usePaperSupportStore"
|
||||||
import { useTopToolsStore } from "../useTopToolsStore"
|
import { useTopToolsStore } from "../useTopToolsStore"
|
||||||
|
|
||||||
const getTagVisibility = (tagCategory?: string) => {
|
const getTagVisibilityByConfig = (tagCategory?: string) => {
|
||||||
const { showTags, showTagsConfigs } = useTopToolsStore.getState()
|
const { showTags, showTagsConfigs } = useTopToolsStore.getState()
|
||||||
if (!showTags) return false
|
if (!showTags) return false
|
||||||
if (tagCategory === "mask") return showTagsConfigs.includes("外框")
|
if (tagCategory === "mask") return showTagsConfigs.includes("外框")
|
||||||
@@ -11,6 +13,16 @@ const getTagVisibility = (tagCategory?: string) => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getObjectTagVisibility = (
|
||||||
|
imageId: string,
|
||||||
|
objectId: number,
|
||||||
|
tagCategory?: string
|
||||||
|
) => {
|
||||||
|
const { pathStatus } = useObjectStore.getState()
|
||||||
|
if (pathStatus[imageId + objectId]?.HIDE) return false
|
||||||
|
return getTagVisibilityByConfig(tagCategory)
|
||||||
|
}
|
||||||
|
|
||||||
const setSelectedItemFalse = (id: number) => {
|
const setSelectedItemFalse = (id: number) => {
|
||||||
if (!id) return
|
if (!id) return
|
||||||
const sameIdItems = usePaperStore.getState().getItemsById(id)
|
const sameIdItems = usePaperStore.getState().getItemsById(id)
|
||||||
@@ -22,7 +34,37 @@ const setSelectedItemFalse = (id: number) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const syncObjectItemsVisibility = (objectId: number, hide: boolean) => {
|
const clearHiddenObjectSelectionState = (imageId: string, objectId: number) => {
|
||||||
|
const { selectedPath, updateSelectedPath } = useObjectStore.getState()
|
||||||
|
if (selectedPath[imageId]?.includes(objectId)) {
|
||||||
|
updateSelectedPath(imageId, "DELETE", objectId)
|
||||||
|
usePaperSupportStore.getState().clearAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
const otherToolsState = useOtherToolsStore.getState()
|
||||||
|
if (
|
||||||
|
otherToolsState.showContextMenu &&
|
||||||
|
otherToolsState.imageId === imageId &&
|
||||||
|
otherToolsState.id === objectId
|
||||||
|
) {
|
||||||
|
otherToolsState.setShowContextMenu({
|
||||||
|
showContextMenu: false,
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
imageId: "",
|
||||||
|
operationId: "",
|
||||||
|
id: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncObjectItemsVisibility = (
|
||||||
|
imageId: string,
|
||||||
|
objectId: number,
|
||||||
|
hide: boolean
|
||||||
|
) => {
|
||||||
const sameIdItems = usePaperStore.getState().getItemsById(objectId)
|
const sameIdItems = usePaperStore.getState().getItemsById(objectId)
|
||||||
if (!sameIdItems?.length) return
|
if (!sameIdItems?.length) return
|
||||||
sameIdItems.forEach((item) => {
|
sameIdItems.forEach((item) => {
|
||||||
@@ -31,7 +73,11 @@ const syncObjectItemsVisibility = (objectId: number, hide: boolean) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (item.data?.type === "tag") {
|
if (item.data?.type === "tag") {
|
||||||
item.visible = getTagVisibility(item.data?.tag_category)
|
item.visible = getObjectTagVisibility(
|
||||||
|
imageId,
|
||||||
|
objectId,
|
||||||
|
item.data?.tag_category
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item.visible = true
|
item.visible = true
|
||||||
@@ -49,8 +95,9 @@ export const toggleObjectHideByShortcut = (
|
|||||||
|
|
||||||
if (hide) {
|
if (hide) {
|
||||||
updatePathStatus(imageId + objectId, "HIDE", hide)
|
updatePathStatus(imageId + objectId, "HIDE", hide)
|
||||||
syncObjectItemsVisibility(objectId, hide)
|
syncObjectItemsVisibility(imageId, objectId, hide)
|
||||||
setSelectedItemFalse(objectId)
|
setSelectedItemFalse(objectId)
|
||||||
|
clearHiddenObjectSelectionState(imageId, objectId)
|
||||||
|
|
||||||
const operationChildren = storeLabel.get(imageId)?.get(operationId) || []
|
const operationChildren = storeLabel.get(imageId)?.get(operationId) || []
|
||||||
const hasVisibleChild = operationChildren.some((child) => {
|
const hasVisibleChild = operationChildren.some((child) => {
|
||||||
@@ -67,5 +114,5 @@ export const toggleObjectHideByShortcut = (
|
|||||||
|
|
||||||
updateOperationStatus(imageId + operationId, "HIDE", hide)
|
updateOperationStatus(imageId + operationId, "HIDE", hide)
|
||||||
updatePathStatus(imageId + objectId, "HIDE", hide)
|
updatePathStatus(imageId + objectId, "HIDE", hide)
|
||||||
syncObjectItemsVisibility(objectId, hide)
|
syncObjectItemsVisibility(imageId, objectId, hide)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user