Fix: issue 11: objects not snapping. and increase snap threshold

This commit is contained in:
Ayobami
2025-07-06 22:06:31 +01:00
parent 20618725d5
commit 34cb733ed7
+126 -73
View File
@@ -412,95 +412,148 @@ export const DockBuilder = () => {
}; };
function edgeDetectionAndSnap(options) { function edgeDetectionAndSnap(options) {
if (editorMemo.getZoom() !== 1) { if (this.isZoomed) {
return; return;
} }
// TODO: Edge detection and snap to object within snap range // TODO: Edge detection and snap to object within snap range
const selectedObj = options.target; if (options && options.target) {
if (!selectedObj.dockData) return; const selectedObj = options.target.setCoords();
// TODO: Detect if the selected object is in the allowed categories // TODO: Detect if the object is within the snap range of the selected object
const snapCategories = [ // This is handled by the edgeDetection function which checks if objects are within snap threshold
DockPanelCategories.Accessories, editorMemo.forEachObject((obj) => {
DockPanelCategories.BoatLift2, if (obj === selectedObj) return;
DockPanelCategories.BoatLift4,
];
if (!snapCategories.includes(selectedObj.dockData.itemName)) return; const detectedObjBound = obj.getBoundingRect();
const selectedObjBound = selectedObj.getBoundingRect();
let closestSnapPoint = null; // Only process image objects that are not snap clones
let minDistance = edgeSnapThreshold; if (!obj.snapClone && obj.type === "image") {
// TODO: handle rotation of 0, 90, 180, 270 degrees
editorMemo.forEachObject((obj) => { // Handle TOP edge snapping
if (obj === selectedObj || !obj.dockData) return; if (edgeDetection(selectedObj, obj, "top")) {
let newTop = selectedObjBound.top;
// TODO: Only consider objects in the allowed categories // Handle different rotation combinations for top snapping
if (!snapCategories.includes(obj.dockData.itemName)) return; if ([0, nintyDeg].includes(obj.angle)) {
if ([oneEightyDeg, twoSeventyDeg].includes(selectedObj.angle)) {
newTop = obj.oCoords.tl.y;
} else {
newTop = obj.oCoords.tl.y - selectedObjBound.height;
}
} else {
if ([oneEightyDeg, twoSeventyDeg].includes(selectedObj.angle)) {
newTop = obj.oCoords.tl.y - detectedObjBound.height;
} else {
newTop =
obj.oCoords.tl.y -
(selectedObjBound.height + detectedObjBound.height);
}
}
// TODO: handle rotation of 0, 90, 180, 270 degrees // Apply the new position
const rotation = obj.angle % 360; selectedObj.setPositionByOrigin(
const isRotated = rotation !== 0 && rotation !== 180; { x: selectedObj.oCoords.tl.x, y: newTop },
"left",
"top"
);
selectedObj.setCoords();
editorMemo.renderAll();
}
// Handle BOTTOM edge snapping
else if (edgeDetection(selectedObj, obj, "bottom")) {
let newTop = selectedObjBound.top;
const objCenter = obj.getCenterPoint(); // Handle different rotation combinations for bottom snapping
const selectedCenter = selectedObj.getCenterPoint(); if ([0, nintyDeg].includes(obj.angle)) {
if ([oneEightyDeg, twoSeventyDeg].includes(selectedObj.angle)) {
newTop =
obj.oCoords.tl.y +
(detectedObjBound.height + selectedObjBound.height);
} else {
newTop = obj.oCoords.tl.y + detectedObjBound.height;
}
} else {
if ([oneEightyDeg, twoSeventyDeg].includes(selectedObj.angle)) {
newTop = obj.oCoords.tl.y + selectedObjBound.height;
} else {
newTop = obj.oCoords.tl.y;
}
}
// Calculate potential snap points // Apply the new position
const snapPoints = []; selectedObj.setPositionByOrigin(
{ x: selectedObj.oCoords.tl.x, y: newTop },
"left",
"top"
);
selectedObj.setCoords();
editorMemo.renderAll();
}
// Handle LEFT edge snapping
else if (edgeDetection(selectedObj, obj, "left")) {
let newLeft = selectedObjBound.left;
// Center point // Handle different rotation combinations for left snapping
snapPoints.push(objCenter); if ([0, twoSeventyDeg].includes(obj.angle)) {
if ([oneEightyDeg, nintyDeg].includes(selectedObj.angle)) {
newLeft = obj.oCoords.tl.x;
} else {
newLeft = obj.oCoords.tl.x - selectedObjBound.width;
}
} else {
if ([oneEightyDeg, nintyDeg].includes(selectedObj.angle)) {
newLeft = obj.oCoords.tl.x - detectedObjBound.width;
} else {
newLeft =
obj.oCoords.tl.x -
(selectedObjBound.width + detectedObjBound.width);
}
}
// Edge points // Apply the new position
if (!isRotated || rotation === 0 || rotation === 180) { selectedObj.setPositionByOrigin(
// Horizontal edges { x: newLeft, y: selectedObj.oCoords.tl.y },
snapPoints.push( "left",
new fabric.Point(objCenter.x, obj.getBoundingRect().top) "top"
); );
snapPoints.push( selectedObj.setCoords();
new fabric.Point( editorMemo.renderAll();
objCenter.x, }
obj.getBoundingRect().top + obj.getBoundingRect().height // Handle RIGHT edge snapping
) else if (edgeDetection(selectedObj, obj, "right")) {
); let newLeft = selectedObjBound.left;
}
if (!isRotated || rotation === 90 || rotation === 270) { // Handle different rotation combinations for right snapping
// Vertical edges if ([0, twoSeventyDeg].includes(obj.angle)) {
snapPoints.push( if ([oneEightyDeg, nintyDeg].includes(selectedObj.angle)) {
new fabric.Point(obj.getBoundingRect().left, objCenter.y) newLeft =
); obj.oCoords.tl.x +
snapPoints.push( (detectedObjBound.width + selectedObjBound.width);
new fabric.Point( } else {
obj.getBoundingRect().left + obj.getBoundingRect().width, newLeft = obj.oCoords.tl.x + detectedObjBound.width;
objCenter.y }
) } else {
); if ([oneEightyDeg, nintyDeg].includes(selectedObj.angle)) {
} newLeft = obj.oCoords.tl.x + selectedObjBound.width;
} else {
newLeft = obj.oCoords.tl.x;
}
}
// Find closest snap point // Apply the new position
snapPoints.forEach((point) => { selectedObj.setPositionByOrigin(
const distance = Math.sqrt( { x: newLeft, y: selectedObj.oCoords.tl.y },
Math.pow(selectedCenter.x - point.x, 2) + "left",
Math.pow(selectedCenter.y - point.y, 2) "top"
); );
selectedObj.setCoords();
if (distance < minDistance) { editorMemo.renderAll();
minDistance = distance; }
closestSnapPoint = point;
} }
}); });
});
// Snap to closest point if found
if (closestSnapPoint) {
const selectedCenter = selectedObj.getCenterPoint();
selectedObj.set({
left: selectedObj.left + (closestSnapPoint.x - selectedCenter.x),
top: selectedObj.top + (closestSnapPoint.y - selectedCenter.y),
});
selectedObj.setCoords();
editorMemo.renderAll();
} }
editorMemo.defaultCursor = "default"; editorMemo.defaultCursor = "default";
@@ -832,13 +885,13 @@ export const DockBuilder = () => {
fabric.devicePixelRatio = 1; fabric.devicePixelRatio = 1;
fabric.Group.prototype.hasControls = true; fabric.Group.prototype.hasControls = true;
fabric.Group.prototype.snapAngle = 45; fabric.Group.prototype.snapAngle = 45;
fabric.Group.prototype.snapThreshold = 5; fabric.Group.prototype.snapThreshold = 10;
fabric.Group.prototype.stroke = "#0f75bc"; fabric.Group.prototype.stroke = "#0f75bc";
fabric.Object.prototype.snapAngle = 45; fabric.Object.prototype.snapAngle = 45;
// Optimize object rendering // Optimize object rendering
fabric.Object.prototype.objectCaching = true; fabric.Object.prototype.objectCaching = true;
fabric.Object.prototype.snapThreshold = 5; fabric.Object.prototype.snapThreshold = 10;
fabric.Object.prototype.setControlsVisibility({ fabric.Object.prototype.setControlsVisibility({
tl: false, //top-left tl: false, //top-left
mt: false, // middle-top mt: false, // middle-top