feat(label): add right select
This commit is contained in:
@@ -318,6 +318,229 @@ const hidePaperContextMenu = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PAPER_OBJECT_TYPES = ["rectangle", "polygon", "brush", "point"] as const
|
||||||
|
const PAPER_CONTEXT_HIT_TYPES = [
|
||||||
|
...PAPER_OBJECT_TYPES,
|
||||||
|
"circle",
|
||||||
|
"mask",
|
||||||
|
"pathBuff",
|
||||||
|
"pathCircle",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const isPaperObjectType = (type: unknown) =>
|
||||||
|
typeof type === "string" &&
|
||||||
|
PAPER_OBJECT_TYPES.includes(type as (typeof PAPER_OBJECT_TYPES)[number])
|
||||||
|
|
||||||
|
const isPaperContextHitType = (type: unknown) =>
|
||||||
|
typeof type === "string" &&
|
||||||
|
PAPER_CONTEXT_HIT_TYPES.includes(
|
||||||
|
type as (typeof PAPER_CONTEXT_HIT_TYPES)[number]
|
||||||
|
)
|
||||||
|
|
||||||
|
const getPaperCursorByMode = (
|
||||||
|
mode: PaperState["mode"] = usePaperStore.getState().mode
|
||||||
|
) => {
|
||||||
|
if (
|
||||||
|
["polygon", "rectangle", "brush", "point", "support"].includes(mode || "")
|
||||||
|
) {
|
||||||
|
return "crosshair"
|
||||||
|
}
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncPaperCursorByMode = (
|
||||||
|
mode: PaperState["mode"] = usePaperStore.getState().mode
|
||||||
|
) => {
|
||||||
|
if (usePaperStore.getState().el) {
|
||||||
|
usePaperStore.getState().el!.style.cursor = getPaperCursorByMode(mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearPaperSelectedObjects = () => {
|
||||||
|
const group = usePaperStore.getState().group
|
||||||
|
if (!group) return
|
||||||
|
|
||||||
|
group
|
||||||
|
.getItems({
|
||||||
|
match: (item: paper.Item) => !!item.data?.selected,
|
||||||
|
})
|
||||||
|
.forEach((item) => {
|
||||||
|
item.data.selected = false
|
||||||
|
})
|
||||||
|
|
||||||
|
usePaperSupportStore.getState().clearAll()
|
||||||
|
|
||||||
|
const activeImage = useBottomToolsStore.getState().activeImage
|
||||||
|
const selectedIds = [
|
||||||
|
...(useObjectStore.getState().selectedPath[activeImage] || []),
|
||||||
|
]
|
||||||
|
|
||||||
|
selectedIds.forEach((id) => {
|
||||||
|
usePaperStore
|
||||||
|
.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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
selectedIds.forEach((id) => {
|
||||||
|
useObjectStore.getState().updateSelectedPath(activeImage, "DELETE", id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyPaperSelectedPath = (item: paper.Path | paper.CompoundPath) => {
|
||||||
|
if (item.data.type === "rectangle" && item instanceof paper.Path) {
|
||||||
|
item.data.selected = true
|
||||||
|
usePaperSupportStore.getState().handleBufferPaths(item)
|
||||||
|
usePaperSupportStore.getState().handleCircles(item)
|
||||||
|
item.fillColor = item.data.fillColor || item.fillColor || null
|
||||||
|
} else if (item.data.type === "brush") {
|
||||||
|
item.data.selected = true
|
||||||
|
if (item instanceof paper.Path) {
|
||||||
|
usePaperSupportStore.getState().handleMask(item)
|
||||||
|
usePaperSupportStore.getState().handleBufferPaths(item)
|
||||||
|
usePaperSupportStore.getState().handleCircles(item)
|
||||||
|
}
|
||||||
|
} else if (item.data.type === "point" && item instanceof paper.Path) {
|
||||||
|
item.data.selected = true
|
||||||
|
usePaperSupportStore.getState().handleMask(item)
|
||||||
|
usePaperSupportStore.getState().handleText(item)
|
||||||
|
usePaperSupportStore.getState().handleBufferPaths(item)
|
||||||
|
usePaperSupportStore.getState().handleCircles(item)
|
||||||
|
} else if (item.data.type === "polygon") {
|
||||||
|
item.data.selected = true
|
||||||
|
if (!(item instanceof paper.Path) || !item.data?.isHollowPolygon) {
|
||||||
|
item.fillColor = item.data.fillColor || item.fillColor || null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item.bringToFront()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPaperSelectionPath = (
|
||||||
|
id: number,
|
||||||
|
localPoint: paper.Point,
|
||||||
|
preferredItem?: paper.Item | null
|
||||||
|
) => {
|
||||||
|
if (
|
||||||
|
preferredItem instanceof paper.Path &&
|
||||||
|
isPaperObjectType(preferredItem.data?.type)
|
||||||
|
) {
|
||||||
|
return preferredItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectPaths = usePaperStore
|
||||||
|
.getState()
|
||||||
|
.getItemsById(id)
|
||||||
|
.filter(
|
||||||
|
(item): item is paper.Path =>
|
||||||
|
item instanceof paper.Path && isPaperObjectType(item.data?.type)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!objectPaths.length) return null
|
||||||
|
if (objectPaths.length === 1) return objectPaths[0]
|
||||||
|
|
||||||
|
let nearestPath = objectPaths[0]
|
||||||
|
for (let index = 1; index < objectPaths.length; index += 1) {
|
||||||
|
const item = objectPaths[index]
|
||||||
|
if (
|
||||||
|
item.getNearestPoint(localPoint).getDistance(localPoint) <
|
||||||
|
nearestPath.getNearestPoint(localPoint).getDistance(localPoint)
|
||||||
|
) {
|
||||||
|
nearestPath = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nearestPath
|
||||||
|
}
|
||||||
|
|
||||||
|
const trySelectPaperObjectByPoint = (clickPoint: paper.Point) => {
|
||||||
|
const group = usePaperStore.getState().group
|
||||||
|
if (!group) return false
|
||||||
|
|
||||||
|
const hitResult = group.hitTest(clickPoint, {
|
||||||
|
segments: true,
|
||||||
|
stroke: true,
|
||||||
|
curves: true,
|
||||||
|
fill: true,
|
||||||
|
guides: false,
|
||||||
|
tolerance: usePaperStore.getState().paperScope
|
||||||
|
? 8 / useTopToolsStore.getState().scale
|
||||||
|
: 0,
|
||||||
|
match: (hit: paper.HitResult) =>
|
||||||
|
!!hit.item.data?.id && isPaperContextHitType(hit.item.data?.type),
|
||||||
|
})
|
||||||
|
|
||||||
|
const id = hitResult?.item?.data?.id
|
||||||
|
if (!id) return false
|
||||||
|
|
||||||
|
clearPaperSelectedObjects()
|
||||||
|
|
||||||
|
const localPoint = group.globalToLocal(clickPoint)
|
||||||
|
const selectedPath = getPaperSelectionPath(id, localPoint, hitResult?.item)
|
||||||
|
const operationId = (
|
||||||
|
selectedPath?.data?.operationId ||
|
||||||
|
usePaperStore.getState().getItemById(id)?.data?.operationId ||
|
||||||
|
hitResult?.item?.data?.operationId ||
|
||||||
|
""
|
||||||
|
).toString()
|
||||||
|
|
||||||
|
usePaperStore
|
||||||
|
.getState()
|
||||||
|
.getItemsById(id)
|
||||||
|
.forEach((item) => {
|
||||||
|
if (!(item instanceof paper.Path || item instanceof paper.CompoundPath))
|
||||||
|
return
|
||||||
|
if (!isPaperObjectType(item.data?.type)) return
|
||||||
|
|
||||||
|
if (item.data.type === "polygon") {
|
||||||
|
applyPaperSelectedPath(item)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
item instanceof paper.CompoundPath ||
|
||||||
|
(selectedPath && item === selectedPath)
|
||||||
|
) {
|
||||||
|
applyPaperSelectedPath(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const activeImage = useBottomToolsStore.getState().activeImage
|
||||||
|
useObjectStore.getState().updateSelectedPath(activeImage, "ADD", id)
|
||||||
|
|
||||||
|
const category = useTopToolsStore
|
||||||
|
.getState()
|
||||||
|
.objectOperations.find(
|
||||||
|
(item) => item.category_id.toString() === operationId
|
||||||
|
)
|
||||||
|
const { top, left } = getShowContextMenuPosition(
|
||||||
|
clickPoint,
|
||||||
|
(category || {}) as Project.LabelSchemaList,
|
||||||
|
5,
|
||||||
|
5
|
||||||
|
)
|
||||||
|
|
||||||
|
useOtherToolsStore.getState().setShowContextMenu({
|
||||||
|
showContextMenu: true,
|
||||||
|
position: { top, left },
|
||||||
|
imageId:
|
||||||
|
selectedPath?.data?.imageId ||
|
||||||
|
hitResult?.item?.data?.imageId ||
|
||||||
|
activeImage,
|
||||||
|
operationId,
|
||||||
|
id,
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
let isMiddleMousePanning = false
|
let isMiddleMousePanning = false
|
||||||
let hoveredBufferPathInfo: {
|
let hoveredBufferPathInfo: {
|
||||||
id: number
|
id: number
|
||||||
@@ -3530,8 +3753,14 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
if (startMiddleMousePan(e.event)) return
|
if (startMiddleMousePan(e.event)) return
|
||||||
if (e.event.button === 2) {
|
if (e.event.button === 2) {
|
||||||
e.event.preventDefault()
|
e.event.preventDefault()
|
||||||
hidePaperContextMenu()
|
if (polygon || points.length) {
|
||||||
undoPolygonPoint()
|
hidePaperContextMenu()
|
||||||
|
undoPolygonPoint()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!trySelectPaperObjectByPoint(e.point)) {
|
||||||
|
hidePaperContextMenu()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (e.event.button !== 0) return
|
if (e.event.button !== 0) return
|
||||||
@@ -4113,8 +4342,18 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
let rect: paper.Path.Rectangle | null
|
let rect: paper.Path.Rectangle | null
|
||||||
let rectangleTool = paperRectangleTool
|
let rectangleTool = paperRectangleTool
|
||||||
|
|
||||||
rectangleTool.onMouseDown = (e: { event: MouseEvent }) => {
|
rectangleTool.onMouseDown = (e: {
|
||||||
|
event: MouseEvent
|
||||||
|
point: paper.Point
|
||||||
|
}) => {
|
||||||
if (startMiddleMousePan(e.event)) return
|
if (startMiddleMousePan(e.event)) return
|
||||||
|
if (e.event.button === 2) {
|
||||||
|
e.event.preventDefault()
|
||||||
|
if (!trySelectPaperObjectByPoint(e.point)) {
|
||||||
|
hidePaperContextMenu()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
if (e.event && e.event.button !== 2)
|
if (e.event && e.event.button !== 2)
|
||||||
useOtherToolsStore.getState().setShowContextMenu({
|
useOtherToolsStore.getState().setShowContextMenu({
|
||||||
showContextMenu: false,
|
showContextMenu: false,
|
||||||
@@ -4463,8 +4702,14 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
if (startMiddleMousePan(e.event)) return
|
if (startMiddleMousePan(e.event)) return
|
||||||
if (e.event.button === 2) {
|
if (e.event.button === 2) {
|
||||||
e.event.preventDefault()
|
e.event.preventDefault()
|
||||||
hidePaperContextMenu()
|
if (myPath || points.length) {
|
||||||
undoBrushPoint()
|
hidePaperContextMenu()
|
||||||
|
undoBrushPoint()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!trySelectPaperObjectByPoint(e.point)) {
|
||||||
|
hidePaperContextMenu()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (e.event.button !== 0) return
|
if (e.event.button !== 0) return
|
||||||
@@ -4934,8 +5179,14 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
if (startMiddleMousePan(e.event)) return
|
if (startMiddleMousePan(e.event)) return
|
||||||
if (e.event.button === 2) {
|
if (e.event.button === 2) {
|
||||||
e.event.preventDefault()
|
e.event.preventDefault()
|
||||||
hidePaperContextMenu()
|
if (myPath || points.length) {
|
||||||
undoPoint()
|
hidePaperContextMenu()
|
||||||
|
undoPoint()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!trySelectPaperObjectByPoint(e.point)) {
|
||||||
|
hidePaperContextMenu()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (e.event.button !== 0) return
|
if (e.event.button !== 0) return
|
||||||
@@ -5426,7 +5677,10 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
clearHoveredBufferPathHighlight()
|
clearHoveredBufferPathHighlight()
|
||||||
circle.strokeWidth = 4
|
circle.strokeWidth = 4
|
||||||
circle.fillColor = new paper.Color("#FFF")
|
circle.fillColor = new paper.Color("#FFF")
|
||||||
if (usePaperStore.getState().el) {
|
if (
|
||||||
|
usePaperStore.getState().mode === "pan" &&
|
||||||
|
usePaperStore.getState().el
|
||||||
|
) {
|
||||||
usePaperStore.getState().el!.style.cursor = "move"
|
usePaperStore.getState().el!.style.cursor = "move"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5436,9 +5690,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
}
|
}
|
||||||
circle.strokeWidth = 2
|
circle.strokeWidth = 2
|
||||||
circle.fillColor = color
|
circle.fillColor = color
|
||||||
if (usePaperStore.getState().el) {
|
syncPaperCursorByMode()
|
||||||
usePaperStore.getState().el!.style.cursor = "default"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return circle
|
return circle
|
||||||
},
|
},
|
||||||
@@ -5485,7 +5737,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
!hoveredPathCircleInfo?.item.parent &&
|
!hoveredPathCircleInfo?.item.parent &&
|
||||||
!hoveredBufferPathInfo
|
!hoveredBufferPathInfo
|
||||||
) {
|
) {
|
||||||
usePaperStore.getState().el!.style.cursor = "default"
|
syncPaperCursorByMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const scheduleClear = () => {
|
const scheduleClear = () => {
|
||||||
@@ -5564,45 +5816,31 @@ export const usePaperStore = create<PaperState>((set) => ({
|
|||||||
switch (modeParam) {
|
switch (modeParam) {
|
||||||
case "pan":
|
case "pan":
|
||||||
usePaperStore.getState().panTool?.activate()
|
usePaperStore.getState().panTool?.activate()
|
||||||
if (usePaperStore.getState().el) {
|
syncPaperCursorByMode(modeParam)
|
||||||
usePaperStore.getState().el!.style.cursor = "default"
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case "polygon":
|
case "polygon":
|
||||||
usePaperStore.getState().polygonTool?.activate()
|
usePaperStore.getState().polygonTool?.activate()
|
||||||
if (usePaperStore.getState().el) {
|
syncPaperCursorByMode(modeParam)
|
||||||
usePaperStore.getState().el!.style.cursor = "crosshair"
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case "rectangle":
|
case "rectangle":
|
||||||
usePaperStore.getState().rectangleTool?.activate()
|
usePaperStore.getState().rectangleTool?.activate()
|
||||||
if (usePaperStore.getState().el) {
|
syncPaperCursorByMode(modeParam)
|
||||||
usePaperStore.getState().el!.style.cursor = "crosshair"
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case "brush":
|
case "brush":
|
||||||
usePaperStore.getState().brushTool?.activate()
|
usePaperStore.getState().brushTool?.activate()
|
||||||
if (usePaperStore.getState().el) {
|
syncPaperCursorByMode(modeParam)
|
||||||
usePaperStore.getState().el!.style.cursor = "crosshair"
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case "point":
|
case "point":
|
||||||
usePaperStore.getState().pointTool?.activate()
|
usePaperStore.getState().pointTool?.activate()
|
||||||
if (usePaperStore.getState().el) {
|
syncPaperCursorByMode(modeParam)
|
||||||
usePaperStore.getState().el!.style.cursor = "crosshair"
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case "support":
|
case "support":
|
||||||
usePaperStore.getState().supportTool?.activate()
|
usePaperStore.getState().supportTool?.activate()
|
||||||
if (usePaperStore.getState().el) {
|
syncPaperCursorByMode(modeParam)
|
||||||
usePaperStore.getState().el!.style.cursor = "crosshair"
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
usePaperStore.getState().viewTool?.activate()
|
usePaperStore.getState().viewTool?.activate()
|
||||||
if (usePaperStore.getState().el) {
|
syncPaperCursorByMode(modeParam)
|
||||||
usePaperStore.getState().el!.style.cursor = "default"
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user