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;
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);
+68 -20
View File
@@ -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[];
};
export const getSnappedPosition = (
pos: { x: number; y: number },
guides: Guide[],
): SnappedPositionResult => {
let x = pos.x;
let y = pos.y;
const activeGuideIds: string[] = [];
type AxisSnapCandidate = {
guideId: string;
delta: number;
distance: number;
};
guides.forEach((guide) => {
if (
guide.orientation === "vertical" &&
Math.abs(pos.x - guide.position) <= SNAP_THRESHOLD
) {
x = guide.position;
activeGuideIds.push(guide.id);
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 (
guide.orientation === "horizontal" &&
Math.abs(pos.y - guide.position) <= SNAP_THRESHOLD
) {
y = guide.position;
activeGuideIds.push(guide.id);
if (!best || distance < best.distance) {
best = {
guideId: guide.id,
delta: guide.position - anchor,
distance,
};
}
});
});
return best;
};
export const getSnappedPosition = (
node: Konva.Node,
guides: Guide[],
): SnappedPositionResult => {
const layer = node.getLayer();
const rect = node.getClientRect({
skipShadow: true,
...(layer ? { relativeTo: layer } : {}),
});
let x = node.x();
let y = node.y();
const activeGuideIds: string[] = [];
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 }));
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 },