fix magnets
This commit is contained in:
@@ -199,7 +199,7 @@ const EditorCanvas = ({ catalogSize }: EditorCanvasProps) => {
|
||||
const node = e.target;
|
||||
if (!node || node.name() === "guide-line") return;
|
||||
|
||||
const snapped = getSnappedPosition({ x: node.x(), y: node.y() }, guides);
|
||||
const snapped = getSnappedPosition(node, guides);
|
||||
|
||||
if (node.x() !== snapped.position.x || node.y() !== snapped.position.y) {
|
||||
node.position(snapped.position);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type Konva from "konva";
|
||||
|
||||
export type Guide = {
|
||||
id: string;
|
||||
orientation: "vertical" | "horizontal";
|
||||
@@ -11,31 +13,77 @@ export type SnappedPositionResult = {
|
||||
activeGuideIds: string[];
|
||||
};
|
||||
|
||||
type AxisSnapCandidate = {
|
||||
guideId: string;
|
||||
delta: number;
|
||||
distance: number;
|
||||
};
|
||||
|
||||
const findBestAxisSnap = (
|
||||
guideInfos: Array<{ id: string; position: number }>,
|
||||
anchors: number[],
|
||||
): AxisSnapCandidate | null => {
|
||||
let best: AxisSnapCandidate | null = null;
|
||||
|
||||
guideInfos.forEach((guide) => {
|
||||
anchors.forEach((anchor) => {
|
||||
const distance = Math.abs(anchor - guide.position);
|
||||
if (distance > SNAP_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!best || distance < best.distance) {
|
||||
best = {
|
||||
guideId: guide.id,
|
||||
delta: guide.position - anchor,
|
||||
distance,
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return best;
|
||||
};
|
||||
|
||||
export const getSnappedPosition = (
|
||||
pos: { x: number; y: number },
|
||||
node: Konva.Node,
|
||||
guides: Guide[],
|
||||
): SnappedPositionResult => {
|
||||
let x = pos.x;
|
||||
let y = pos.y;
|
||||
const layer = node.getLayer();
|
||||
const rect = node.getClientRect({
|
||||
skipShadow: true,
|
||||
...(layer ? { relativeTo: layer } : {}),
|
||||
});
|
||||
let x = node.x();
|
||||
let y = node.y();
|
||||
const activeGuideIds: string[] = [];
|
||||
|
||||
guides.forEach((guide) => {
|
||||
if (
|
||||
guide.orientation === "vertical" &&
|
||||
Math.abs(pos.x - guide.position) <= SNAP_THRESHOLD
|
||||
) {
|
||||
x = guide.position;
|
||||
activeGuideIds.push(guide.id);
|
||||
}
|
||||
const verticalGuides = guides
|
||||
.filter((guide) => guide.orientation === "vertical")
|
||||
.map((guide) => ({ id: guide.id, position: guide.position }));
|
||||
const horizontalGuides = guides
|
||||
.filter((guide) => guide.orientation === "horizontal")
|
||||
.map((guide) => ({ id: guide.id, position: guide.position }));
|
||||
|
||||
if (
|
||||
guide.orientation === "horizontal" &&
|
||||
Math.abs(pos.y - guide.position) <= SNAP_THRESHOLD
|
||||
) {
|
||||
y = guide.position;
|
||||
activeGuideIds.push(guide.id);
|
||||
}
|
||||
});
|
||||
const verticalSnap = findBestAxisSnap(verticalGuides, [
|
||||
rect.x,
|
||||
rect.x + rect.width / 2,
|
||||
rect.x + rect.width,
|
||||
]);
|
||||
if (verticalSnap) {
|
||||
x += verticalSnap.delta;
|
||||
activeGuideIds.push(verticalSnap.guideId);
|
||||
}
|
||||
|
||||
const horizontalSnap = findBestAxisSnap(horizontalGuides, [
|
||||
rect.y,
|
||||
rect.y + rect.height / 2,
|
||||
rect.y + rect.height,
|
||||
]);
|
||||
if (horizontalSnap) {
|
||||
y += horizontalSnap.delta;
|
||||
activeGuideIds.push(horizontalSnap.guideId);
|
||||
}
|
||||
|
||||
return {
|
||||
position: { x, y },
|
||||
|
||||
Reference in New Issue
Block a user