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