fix(tag): bug
This commit is contained in:
@@ -166,6 +166,24 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
[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 = () => {
|
||||
usePaperStore
|
||||
@@ -215,11 +233,16 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(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]?.includes(id)) {
|
||||
if (pressShift) {
|
||||
if (getItemsById(id)?.length) {
|
||||
getItemsById(id).forEach((item) => {
|
||||
if (objectItems.length && targetItem) {
|
||||
objectItems.forEach((item) => {
|
||||
if (item instanceof paper.Path) {
|
||||
handleSelectedPath(item)
|
||||
} else if (item instanceof paper.CompoundPath) {
|
||||
@@ -228,13 +251,14 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
else item.data.selected = true
|
||||
}
|
||||
})
|
||||
bringTagItemsToFront(id)
|
||||
let category = useTopToolsStore
|
||||
.getState()
|
||||
.objectOperations.find(
|
||||
(item) => item.category_id.toString() === operationId
|
||||
)
|
||||
const globalPosition = getItemById(id)!.globalMatrix.transform(
|
||||
getItemById(id)!.position
|
||||
const globalPosition = targetItem.globalMatrix.transform(
|
||||
targetItem.position
|
||||
)
|
||||
const { top, left } = getShowContextMenuPosition(
|
||||
globalPosition,
|
||||
@@ -251,8 +275,9 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
} else {
|
||||
clearSelectedItems()
|
||||
selectedPath[activeImage].forEach((selectedId) => {
|
||||
if (getItemsById(selectedId)?.length) {
|
||||
getItemsById(selectedId).forEach((item) => {
|
||||
const selectedObjectItems = getObjectItemsById(selectedId)
|
||||
if (selectedObjectItems.length) {
|
||||
selectedObjectItems.forEach((item) => {
|
||||
cancelSelectedPathColor(item)
|
||||
})
|
||||
useOtherToolsStore.getState().setShowContextMenu({
|
||||
@@ -267,8 +292,8 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
})
|
||||
}
|
||||
})
|
||||
if (getItemsById(id)?.length) {
|
||||
getItemsById(id).forEach((item) => {
|
||||
if (objectItems.length && targetItem) {
|
||||
objectItems.forEach((item) => {
|
||||
if (item instanceof paper.Path) {
|
||||
handleSelectedPath(item)
|
||||
} else if (item instanceof paper.CompoundPath) {
|
||||
@@ -277,13 +302,14 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
else item.data.selected = true
|
||||
}
|
||||
})
|
||||
bringTagItemsToFront(id)
|
||||
let category = useTopToolsStore
|
||||
.getState()
|
||||
.objectOperations.find(
|
||||
(item) => item.category_id.toString() === operationId
|
||||
)
|
||||
const globalPosition = getItemById(id)!.globalMatrix.transform(
|
||||
getItemById(id)!.position
|
||||
const globalPosition = targetItem.globalMatrix.transform(
|
||||
targetItem.position
|
||||
)
|
||||
const { top, left } = getShowContextMenuPosition(
|
||||
globalPosition,
|
||||
@@ -302,8 +328,8 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
} else {
|
||||
clearSelectedItems()
|
||||
updateSelectedPath(activeImage, "DELETE", id)
|
||||
if (getItemsById(id)?.length) {
|
||||
getItemsById(id).forEach((item) => {
|
||||
if (objectItems.length) {
|
||||
objectItems.forEach((item) => {
|
||||
cancelSelectedPathColor(item)
|
||||
})
|
||||
useOtherToolsStore.getState().setShowContextMenu({
|
||||
@@ -321,8 +347,8 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
} else {
|
||||
clearSelectedItems()
|
||||
updateSelectedPath(activeImage, "ADD", id)
|
||||
if (getItemsById(id)?.length) {
|
||||
getItemsById(id).forEach((item) => {
|
||||
if (objectItems.length && targetItem) {
|
||||
objectItems.forEach((item) => {
|
||||
if (item instanceof paper.Path) {
|
||||
handleSelectedPath(item)
|
||||
} else if (item instanceof paper.CompoundPath) {
|
||||
@@ -337,14 +363,15 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
// item.fillColor = item.data?.fillColor;
|
||||
// item.bringToFront();
|
||||
})
|
||||
bringTagItemsToFront(id)
|
||||
|
||||
let category = useTopToolsStore
|
||||
.getState()
|
||||
.objectOperations.find(
|
||||
(item) => item.category_id.toString() === operationId
|
||||
)
|
||||
const globalPosition = getItemById(id)!.globalMatrix.transform(
|
||||
getItemById(id)!.position
|
||||
const globalPosition = targetItem.globalMatrix.transform(
|
||||
targetItem.position
|
||||
)
|
||||
const { top, left } = getShowContextMenuPosition(
|
||||
globalPosition,
|
||||
@@ -362,8 +389,10 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
},
|
||||
[
|
||||
activeImage,
|
||||
bringTagItemsToFront,
|
||||
getObjectItemsById,
|
||||
getItemById,
|
||||
getItemsById,
|
||||
pathStatus,
|
||||
pressShift,
|
||||
selectedPath,
|
||||
updateSelectedPath,
|
||||
@@ -889,10 +918,13 @@ const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
|
||||
: "var(--mantine-color-gray-0)"
|
||||
}
|
||||
c={isSelected ? "white" : undefined}
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
if (isChildHide) return
|
||||
handleSelect(child[0], operationId)
|
||||
}
|
||||
style={{ cursor: "pointer" }}>
|
||||
}}
|
||||
style={{
|
||||
cursor: isChildHide ? "default" : "pointer",
|
||||
}}>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Group gap="xs">
|
||||
<ActionIcon
|
||||
|
||||
@@ -20,6 +20,7 @@ import { usePaperSupportStore } from "./usePaperSupportStore"
|
||||
import { useRightToolsStore } from "./useRightToolsStore"
|
||||
import { DEFAULT_NODE_SIZE, useTopToolsStore } from "./useTopToolsStore"
|
||||
import { safeClone } from "./utils/clone"
|
||||
import { getObjectTagVisibility } from "./utils/objectVisibility"
|
||||
|
||||
interface ContinuePolygonTarget {
|
||||
imageId: string
|
||||
@@ -216,6 +217,16 @@ const initialPaperState = {
|
||||
reciprocalRasterScale: {},
|
||||
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 group = usePaperStore.getState().group!
|
||||
const imageId = useBottomToolsStore.getState().activeImage
|
||||
@@ -450,12 +461,7 @@ const clearPaperSelectedObjects = () => {
|
||||
.getState()
|
||||
.getItemsById(id)
|
||||
.forEach((item) => {
|
||||
if (
|
||||
(item instanceof paper.Path || item instanceof paper.CompoundPath) &&
|
||||
["rectangle", "polygon"].includes(item.data?.type || "")
|
||||
) {
|
||||
item.fillColor = item.data?.blankColor || item.fillColor || null
|
||||
}
|
||||
resetPaperShapeFillColor(item)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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) => {
|
||||
if (item.data.type === "rectangle" && item instanceof paper.Path) {
|
||||
item.data.selected = true
|
||||
@@ -2011,15 +2027,14 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
type: "tag",
|
||||
},
|
||||
})
|
||||
// 标识位为true时:选中路径隐藏tags; 没选中显示tags
|
||||
const configs = useTopToolsStore.getState().showTagsConfigs
|
||||
// 仅恢复当前应显示的标签,隐藏对象的标签保持不可见
|
||||
if (useTopToolsStore.getState().showTags) {
|
||||
const setTagVisibleByConfig = (tag: any) => {
|
||||
if (tag.data.tag_category === "mask")
|
||||
tag.visible = configs.includes("外框")
|
||||
else if (tag.data.tag_category === "point_text")
|
||||
tag.visible = configs.includes("点ID")
|
||||
else tag.visible = true
|
||||
tag.visible = getObjectTagVisibility(
|
||||
useBottomToolsStore.getState().activeImage,
|
||||
Number(tag.data?.id),
|
||||
tag.data?.tag_category
|
||||
)
|
||||
}
|
||||
lastTags.forEach(setTagVisibleByConfig)
|
||||
tags.forEach(setTagVisibleByConfig)
|
||||
@@ -3147,6 +3162,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
})
|
||||
)
|
||||
polygon.data = Object.assign({ type: "polygon", ...option }, data)
|
||||
insertItemBelowTags(polygon)
|
||||
points?.forEach((point) => {
|
||||
polygon.add(point)
|
||||
})
|
||||
@@ -3219,6 +3235,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
})
|
||||
)
|
||||
compoundPath.data = Object.assign({ type: "polygon", ...option }, data)
|
||||
insertItemBelowTags(compoundPath)
|
||||
compoundPath.onMouseDown = (e: {
|
||||
event: MouseEvent
|
||||
point: paper.Point
|
||||
@@ -4606,8 +4623,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
.getState()
|
||||
.group!.getItems({})
|
||||
.forEach((item) => {
|
||||
// clear color
|
||||
item.fillColor = item?.data?.blankColor
|
||||
resetPaperShapeFillColor(item)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4803,6 +4819,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
Object.assign(option, { strokeScaling: false })
|
||||
)
|
||||
rect.data = Object.assign({ type: "rectangle", ...option }, data)
|
||||
insertItemBelowTags(rect)
|
||||
rect.onMouseEnter = (_e: paper.MouseEvent) => {
|
||||
// if (usePaperStore.getState().mode === "pan") {
|
||||
// e.target.strokeWidth += 2;
|
||||
@@ -5045,6 +5062,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
)
|
||||
)
|
||||
brush.data = Object.assign({ type: "brush", ...option }, data)
|
||||
insertItemBelowTags(brush)
|
||||
// points?.forEach((point) => {
|
||||
// brush.add(point);
|
||||
// });
|
||||
@@ -5545,6 +5563,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
const newScale = useTopToolsStore.getState().scale / currentScaling
|
||||
myCircle.scale(newScale / currentScaling)
|
||||
myCircle.data = Object.assign({ type: "circle", ...option }, data)
|
||||
insertItemBelowTags(myCircle)
|
||||
syncPaperCircleDiameter(myCircle)
|
||||
myCircle.onMouseDown = (e: { event: MouseEvent; point: paper.Point }) => {
|
||||
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)
|
||||
insertItemBelowTags(myCircleLine)
|
||||
return myCircleLine
|
||||
},
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useLabelStore } from "./store"
|
||||
import { useBottomToolsStore } from "./useBottomToolsStore"
|
||||
import { usePaperStore } from "./usePaperStore"
|
||||
import { useTopToolsStore } from "./useTopToolsStore"
|
||||
import { getObjectTagVisibility } from "./utils/objectVisibility"
|
||||
|
||||
const TAG_FONT_SIZE = 12
|
||||
const TAG_VERTICAL_GAP = 8
|
||||
@@ -159,13 +160,12 @@ const useRenderTag = () => {
|
||||
const activeImage = useBottomToolsStore.getState().activeImage
|
||||
const group = usePaperStore.getState().group
|
||||
if (!group) return
|
||||
const visible = useTopToolsStore.getState().showTags
|
||||
const configs = useTopToolsStore.getState().showTagsConfigs
|
||||
const groupScale =
|
||||
Number.isFinite(group.scaling?.x) && group.scaling.x !== 0
|
||||
? group.scaling.x
|
||||
: 1
|
||||
const applyPointTagCompensation = (
|
||||
const applyScreenSpaceTagCompensation = (
|
||||
item: paper.Item,
|
||||
anchor: [number, number]
|
||||
) => {
|
||||
@@ -235,7 +235,7 @@ const useRenderTag = () => {
|
||||
tag_anchor: tagAnchor,
|
||||
},
|
||||
parent: group,
|
||||
visible,
|
||||
visible: getObjectTagVisibility(activeImage, id, "text"),
|
||||
})
|
||||
text.translate(
|
||||
new paper.Point(
|
||||
@@ -259,8 +259,10 @@ const useRenderTag = () => {
|
||||
tag_anchor: tagAnchor,
|
||||
},
|
||||
parent: group,
|
||||
visible,
|
||||
visible: getObjectTagVisibility(activeImage, id, "text_mask"),
|
||||
})
|
||||
applyScreenSpaceTagCompensation(text, tagAnchor)
|
||||
applyScreenSpaceTagCompensation(textMask, tagAnchor)
|
||||
text.bringToFront()
|
||||
}
|
||||
|
||||
@@ -276,7 +278,7 @@ const useRenderTag = () => {
|
||||
tag_category: "mask",
|
||||
},
|
||||
parent: group,
|
||||
visible: visible && configs.includes("外框"),
|
||||
visible: getObjectTagVisibility(activeImage, id, "mask"),
|
||||
})
|
||||
// 标注对象点id
|
||||
if (path instanceof paper.CompoundPath) {
|
||||
@@ -301,9 +303,9 @@ const useRenderTag = () => {
|
||||
tag_anchor: pointTextPosition,
|
||||
},
|
||||
parent: group,
|
||||
visible: visible && configs.includes("点ID"),
|
||||
visible: getObjectTagVisibility(activeImage, id, "point_text"),
|
||||
})
|
||||
applyPointTagCompensation(pointText, pointTextPosition)
|
||||
applyScreenSpaceTagCompensation(pointText, pointTextPosition)
|
||||
index++
|
||||
})
|
||||
})
|
||||
@@ -327,9 +329,9 @@ const useRenderTag = () => {
|
||||
tag_anchor: pointTextPosition,
|
||||
},
|
||||
parent: group,
|
||||
visible: visible && configs.includes("点ID"),
|
||||
visible: getObjectTagVisibility(activeImage, id, "point_text"),
|
||||
})
|
||||
applyPointTagCompensation(pointText, pointTextPosition)
|
||||
applyScreenSpaceTagCompensation(pointText, pointTextPosition)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ import { usePaperStore } from "../usePaperStore"
|
||||
import { usePaperSupportStore } from "../usePaperSupportStore"
|
||||
import { useTopToolsStore } from "../useTopToolsStore"
|
||||
|
||||
const getTagVisibility = (tagCategory?: string) => {
|
||||
const getTagVisibilityByConfig = (tagCategory?: string) => {
|
||||
const { showTags, showTagsConfigs } = useTopToolsStore.getState()
|
||||
if (!showTags) return false
|
||||
if (tagCategory === "mask") return showTagsConfigs.includes("外框")
|
||||
@@ -13,6 +13,16 @@ const getTagVisibility = (tagCategory?: string) => {
|
||||
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) => {
|
||||
if (!id) return
|
||||
const sameIdItems = usePaperStore.getState().getItemsById(id)
|
||||
@@ -50,7 +60,11 @@ const clearHiddenObjectSelectionState = (imageId: string, objectId: number) => {
|
||||
}
|
||||
}
|
||||
|
||||
const syncObjectItemsVisibility = (objectId: number, hide: boolean) => {
|
||||
const syncObjectItemsVisibility = (
|
||||
imageId: string,
|
||||
objectId: number,
|
||||
hide: boolean
|
||||
) => {
|
||||
const sameIdItems = usePaperStore.getState().getItemsById(objectId)
|
||||
if (!sameIdItems?.length) return
|
||||
sameIdItems.forEach((item) => {
|
||||
@@ -59,7 +73,11 @@ const syncObjectItemsVisibility = (objectId: number, hide: boolean) => {
|
||||
return
|
||||
}
|
||||
if (item.data?.type === "tag") {
|
||||
item.visible = getTagVisibility(item.data?.tag_category)
|
||||
item.visible = getObjectTagVisibility(
|
||||
imageId,
|
||||
objectId,
|
||||
item.data?.tag_category
|
||||
)
|
||||
return
|
||||
}
|
||||
item.visible = true
|
||||
@@ -77,7 +95,7 @@ export const toggleObjectHideByShortcut = (
|
||||
|
||||
if (hide) {
|
||||
updatePathStatus(imageId + objectId, "HIDE", hide)
|
||||
syncObjectItemsVisibility(objectId, hide)
|
||||
syncObjectItemsVisibility(imageId, objectId, hide)
|
||||
setSelectedItemFalse(objectId)
|
||||
clearHiddenObjectSelectionState(imageId, objectId)
|
||||
|
||||
@@ -96,5 +114,5 @@ export const toggleObjectHideByShortcut = (
|
||||
|
||||
updateOperationStatus(imageId + operationId, "HIDE", hide)
|
||||
updatePathStatus(imageId + objectId, "HIDE", hide)
|
||||
syncObjectItemsVisibility(objectId, hide)
|
||||
syncObjectItemsVisibility(imageId, objectId, hide)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user