fix(point): move

This commit is contained in:
zhangheng
2026-04-15 11:04:05 +08:00
parent 9b1f0db3b2
commit d3d9e8385b

View File

@@ -462,6 +462,122 @@ const getPaperSelectionPath = (
return nearestPath
}
const getNearestPaperPathSegmentIndex = (
path: paper.Path,
localPoint: paper.Point
) => {
let nearestIndex = 0
let nearestDistance = Infinity
path.segments.forEach((segment, index) => {
const distance = segment.point.getDistance(localPoint)
if (distance < nearestDistance) {
nearestDistance = distance
nearestIndex = index
}
})
return nearestIndex
}
const normalizePointPanHitResult = (
hitResult: paper.HitResult | null,
localPoint: paper.Point
) => {
if (!hitResult?.item?.data?.id || hitResult.item.data?.type !== "circle") {
return hitResult
}
const selectedPath = getPaperSelectionPath(hitResult.item.data.id, localPoint)
if (
!(selectedPath instanceof paper.Path) ||
selectedPath.data?.type !== "point" ||
!selectedPath.segments.length
) {
return hitResult
}
const segmentIndex = getNearestPaperPathSegmentIndex(selectedPath, localPoint)
return {
...hitResult,
item: selectedPath,
type: "segment",
segment: selectedPath.segments[segmentIndex],
} as paper.HitResult
}
const getPointCirclesById = (id: number) =>
(usePaperStore.getState().group?.getItems({
data: {
id,
type: "circle",
},
}) as paper.Path.Circle[]) || []
const createPointCircleForPath = (
path: paper.Path,
point: paper.Point,
index: number
) => {
const circle = usePaperStore
.getState()
.getPointCircle(point, index, path.data.id, path.data.blankColor)
circle.data = Object.assign({}, circle.data, {
id: path.data.id,
imageId: path.data.imageId,
operationId: path.data.operationId,
text: index + 1,
fillColor: path.data.blankColor,
strokeColor: path.data.strokeColor,
})
circle.fillColor = path.data.blankColor || circle.fillColor || null
circle.strokeColor = path.data.strokeColor || circle.strokeColor || null
return circle
}
const syncPointCirclesWithPath = (path: paper.Path) => {
if (path.data?.type !== "point" || !path.data?.id) return []
const unusedCircles = getPointCirclesById(path.data.id).slice()
const orderedCircles = path.segments.map((segment, index) => {
const matchedCircleIndex = unusedCircles.findIndex((circle) => {
return (
circle.position.getDistance(segment.point) <= 0.01 ||
circle.contains(segment.point)
)
})
const circle =
matchedCircleIndex >= 0
? unusedCircles.splice(matchedCircleIndex, 1)[0]
: createPointCircleForPath(path, segment.point, index)
circle.position.x = segment.point.x
circle.position.y = segment.point.y
circle.data = Object.assign({}, circle.data, {
id: path.data.id,
imageId: path.data.imageId,
operationId: path.data.operationId,
text: index + 1,
fillColor: path.data.blankColor,
strokeColor: path.data.strokeColor,
})
circle.fillColor = path.data.blankColor || circle.fillColor || null
circle.strokeColor = path.data.strokeColor || circle.strokeColor || null
return circle
})
unusedCircles.forEach((circle) => {
circle.remove()
})
return orderedCircles
}
const trySelectPaperObjectByPoint = (clickPoint: paper.Point) => {
const group = usePaperStore.getState().group
if (!group) return false
@@ -1090,8 +1206,6 @@ export const usePaperStore = create<PaperState>((set) => ({
? baseTolerance / useTopToolsStore.getState().scale
: 0
false && getPanHitTolerance
const createPanHitOptions = (
tolerance: number,
match: (hit: paper.HitResult) => boolean
@@ -1115,7 +1229,7 @@ export const usePaperStore = create<PaperState>((set) => ({
if (hoveredCircleInfo) {
const pointHit = group.hitTest(
projectPoint,
createPanHitOptions(0, (hit) => {
createPanHitOptions(getPanHitTolerance(), (hit) => {
return (
hit.item.data?.type === "pathCircle" &&
hit.item.data?.id === hoveredCircleInfo.id &&
@@ -1132,7 +1246,7 @@ export const usePaperStore = create<PaperState>((set) => ({
if (hoveredBufferInfo) {
const edgeHit = group.hitTest(
projectPoint,
createPanHitOptions(0, (hit) => {
createPanHitOptions(getPanHitTolerance(), (hit) => {
return (
hit.item.data?.type === "pathBuff" &&
hit.item.data?.id === hoveredBufferInfo.id &&
@@ -1145,8 +1259,8 @@ export const usePaperStore = create<PaperState>((set) => ({
return group.hitTest(
projectPoint,
createPanHitOptions(0, (hit) =>
["rectangle", "polygon", "brush", "point"].includes(
createPanHitOptions(getPanHitTolerance(), (hit) =>
["rectangle", "polygon", "brush", "point", "circle"].includes(
hit.item.data?.type || ""
)
)
@@ -1197,6 +1311,7 @@ export const usePaperStore = create<PaperState>((set) => ({
hasExceededPanDragThreshold = false
let hitResult = resolvePanHitResult(e.point)
hitResult = normalizePointPanHitResult(hitResult, point)
console.log("hitResult", hitResult)
const hoveredBufferInfo = hoveredBufferPathInfo?.path.parent
? hoveredBufferPathInfo
@@ -1475,27 +1590,26 @@ export const usePaperStore = create<PaperState>((set) => ({
activePath = hitResult.item as paper.Path
}
} else if (hitResult.item.data.type === "point") {
// 只有点击圆才视为选中
if (hitResult.type === "segment") {
// Path 类型
if (hitResult.item instanceof paper.Path) {
if (!hitResult.item.data.selected) {
hitResult.item.data.selected = true
// 绘制遮罩
usePaperSupportStore.getState().handleMask(hitResult.item)
// 绘制点对应的数字
usePaperSupportStore
.getState()
.handleText(hitResult.item as paper.Path)
// 绘制选中边
usePaperSupportStore
.getState()
.handleBufferPaths(hitResult.item)
// 绘制选中圆
usePaperSupportStore.getState().handleCircles(hitResult.item)
}
activePath = hitResult.item as paper.Path
if (
["segment", "stroke"].includes(hitResult.type) &&
hitResult.item instanceof paper.Path
) {
if (!hitResult.item.data.selected) {
hitResult.item.data.selected = true
// 绘制遮罩
usePaperSupportStore.getState().handleMask(hitResult.item)
// 绘制点对应的数字
usePaperSupportStore
.getState()
.handleText(hitResult.item as paper.Path)
// 绘制选中边
usePaperSupportStore
.getState()
.handleBufferPaths(hitResult.item)
// 绘制选中圆
usePaperSupportStore.getState().handleCircles(hitResult.item)
}
activePath = hitResult.item as paper.Path
}
} else if (
hitResult.item.data.type === "pathBuff" ||
@@ -1598,21 +1712,7 @@ export const usePaperStore = create<PaperState>((set) => ({
}
if (currentPath.data.type === "point") {
usePaperSupportStore.getState().handleText(currentPath)
let circles = usePaperStore.getState().group!.getItems({
data: {
id: currentPath.data.id,
type: "circle",
},
}) as paper.Path[]
currentPath.segments.forEach((segment, index) => {
let findIndex = circles.findIndex((circle) => {
return circle.contains(segment.point)
})
circles[index].data = Object.assign({}, circles[index]?.data, {
text: findIndex + 1,
})
})
syncPointCirclesWithPath(currentPath)
usePaperSupportStore.getState().handleBufferPaths(currentPath)
usePaperSupportStore.getState().handleCircles(currentPath)
}
@@ -1677,15 +1777,9 @@ export const usePaperStore = create<PaperState>((set) => ({
}
} else {
activePath.insert(hitIndex + 1, hitResult.location.point)
activePath?.data?.type === "point" &&
usePaperStore
.getState()
.getPointCircle(
hitResult.location.point,
hitIndex + 1,
activePath.data.id,
activePath.data.blankColor
)
if (activePath?.data?.type === "point") {
syncPointCirclesWithPath(activePath)
}
activePath.bringToFront()
usePaperSupportStore.getState().handleBufferPaths(activePath)
usePaperSupportStore.getState().handleCircles(activePath)
@@ -1699,21 +1793,7 @@ export const usePaperStore = create<PaperState>((set) => ({
if (activePath?.data?.type === "point") {
// 绘制点对应的数字
usePaperSupportStore.getState().handleText(activePath)
let circles = usePaperStore.getState().group!.getItems({
data: {
id: activePath.data.id,
type: "circle",
},
}) as paper.Path[]
activePath.segments.forEach((segment, index) => {
let findIndex = circles.findIndex((circle) => {
return circle.contains(segment.point)
})
circles[index].data = Object.assign({}, circles[index]?.data, {
text: findIndex + 1,
})
})
syncPointCirclesWithPath(activePath)
usePaperSupportStore.getState().handleBufferPaths(activePath)
usePaperSupportStore.getState().handleCircles(activePath)
}
@@ -1807,39 +1887,7 @@ export const usePaperStore = create<PaperState>((set) => ({
usePaperSupportStore.getState().handleMask(hitResult.item)
}
if (activePath?.data?.type === "point") {
let paths = usePaperStore.getState().group!.getItems({
data: {
id: activePath.data.id,
// text: activePath.segments.length - hitIndex + 1,
type: "circle",
},
}) as paper.Path[]
// paths = paths.filter((item) => {
// if (item.data.text === hitIndex + 1) item.remove();
// return item.data.text !== hitIndex + 1;
// });
paths = paths.filter((circle) => {
let findIndex = activePath.segments.findIndex((segment) => {
return circle.contains(segment.point)
})
if (findIndex === -1) {
circle.remove()
return false
} else {
return true
}
})
// 1. 对数组按照 text 属性进行排序
let sortedArr = paths
.slice()
.sort((a, b) => a.data.text - b.data.text)
// 2. 重新赋值 text 属性为从 1 开始的连续自然数
sortedArr.forEach((item, index) => {
item.data.text = index + 1
})
syncPointCirclesWithPath(activePath)
// paths.forEach((child) => {
// if (
@@ -2083,27 +2131,11 @@ export const usePaperStore = create<PaperState>((set) => ({
]!.position.y = point!.y
usePaperSupportStore.getState().handleMask(path)
} else if (path.data.type === "point") {
let circles = usePaperStore.getState().group!.getItems({
data: {
id: path.data.id,
type: "circle",
},
}) as paper.Path[]
const circles = syncPointCirclesWithPath(path)
// let index = path.segments.length - hitIndex - 1
// let index = hitIndex;
// 移动点
if (circles && circles.length) {
// let circle = circles.find(
// (item) => item.data.text === index + 1
// );
let circle = circles.find((circle) => {
return circle.contains(path.segments[hitIndex].point)
})
circle!.position.x = point!.x
circle!.position.y = point!.y
if (circles[hitIndex]) {
circles[hitIndex].position.x = point!.x
circles[hitIndex].position.y = point!.y
}
// 移动路径
path.segments[hitIndex].point.x = point!.x
@@ -2315,45 +2347,12 @@ export const usePaperStore = create<PaperState>((set) => ({
}
const handlePointIntersectRaster = (path: paper.Path) => {
let circles = usePaperStore.getState().group!.getItems({
data: {
id: path.data.id,
type: "circle",
},
}) as paper.Path[]
// 去除超出图片边界的部分
let newCircles = circles.filter((circle) => {
if (
!usePaperStore
.getState()
.rasterPath!.bounds.contains(circle.bounds.center)
) {
circle.remove()
return false
} else {
return true
}
})
// 1. 对数组按照 text 属性进行排序
let sortedArr = newCircles
.slice()
.sort((a, b) => a.data.text - b.data.text)
// 2. 重新赋值 text 属性为从 1 开始的连续自然数
sortedArr.forEach((item, index) => {
item.data.text = index + 1
})
// newCircles.forEach((circle, circleIndex) => {
// // 重新设置显示数字
// circle.data.text = circleIndex + 1;
// });
path.segments = path.segments.filter((segment) => {
return usePaperStore
.getState()
.rasterPath!.bounds.contains(segment.point)
})
syncPointCirclesWithPath(path)
// 去除超出图片边界的部分 end
usePaperSupportStore.getState().handleMask(path)
usePaperSupportStore.getState().handleBufferPaths(path)