fix magnets

This commit is contained in:
hamid zarghami
2026-04-26 12:01:54 +03:30
parent a10c618113
commit 4fb19ed576
2 changed files with 68 additions and 20 deletions
+1 -1
View File
@@ -199,7 +199,7 @@ const EditorCanvas = ({ catalogSize }: EditorCanvasProps) => {
const node = e.target; const node = e.target;
if (!node || node.name() === "guide-line") return; 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) { if (node.x() !== snapped.position.x || node.y() !== snapped.position.y) {
node.position(snapped.position); node.position(snapped.position);
+67 -19
View File
@@ -1,3 +1,5 @@
import type Konva from "konva";
export type Guide = { export type Guide = {
id: string; id: string;
orientation: "vertical" | "horizontal"; orientation: "vertical" | "horizontal";
@@ -11,31 +13,77 @@ export type SnappedPositionResult = {
activeGuideIds: string[]; 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 = ( export const getSnappedPosition = (
pos: { x: number; y: number }, node: Konva.Node,
guides: Guide[], guides: Guide[],
): SnappedPositionResult => { ): SnappedPositionResult => {
let x = pos.x; const layer = node.getLayer();
let y = pos.y; const rect = node.getClientRect({
skipShadow: true,
...(layer ? { relativeTo: layer } : {}),
});
let x = node.x();
let y = node.y();
const activeGuideIds: string[] = []; const activeGuideIds: string[] = [];
guides.forEach((guide) => { const verticalGuides = guides
if ( .filter((guide) => guide.orientation === "vertical")
guide.orientation === "vertical" && .map((guide) => ({ id: guide.id, position: guide.position }));
Math.abs(pos.x - guide.position) <= SNAP_THRESHOLD const horizontalGuides = guides
) { .filter((guide) => guide.orientation === "horizontal")
x = guide.position; .map((guide) => ({ id: guide.id, position: guide.position }));
activeGuideIds.push(guide.id);
}
if ( const verticalSnap = findBestAxisSnap(verticalGuides, [
guide.orientation === "horizontal" && rect.x,
Math.abs(pos.y - guide.position) <= SNAP_THRESHOLD rect.x + rect.width / 2,
) { rect.x + rect.width,
y = guide.position; ]);
activeGuideIds.push(guide.id); 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 { return {
position: { x, y }, position: { x, y },