fix magnets
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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 },
|
||||||
|
|||||||
Reference in New Issue
Block a user