Skip to content

Instantly share code, notes, and snippets.

@vasiliishvakin
Created June 4, 2023 09:43
Show Gist options
  • Save vasiliishvakin/da20f7745ff0afce36a5bc5dc47dcc6c to your computer and use it in GitHub Desktop.
Save vasiliishvakin/da20f7745ff0afce36a5bc5dc47dcc6c to your computer and use it in GitHub Desktop.
(() => {
// Create the area object
const areaObject = new fabric.Rect({
width: 200,
height: 200,
fill: "transparent",
stroke: "red",
strokeWidth: 2,
selectable: false,
original: { isBase: true },
});
// Create a regular object (rectangle)
const regularObject = new fabric.Rect({
width: 100,
height: 100,
fill: "blue",
left: 50,
top: 50,
});
// Initialize the canvas
const canvas = new fabric.Canvas("canvas-container", {
width: 400,
height: 400,
});
// Add the area object to the canvas
canvas.add(areaObject);
// Add the regular object to the canvas
canvas.add(regularObject);
// Utility function to check intersection between two objects
function checkIntersection(obj1, obj2) {
const rect1 = obj1.getBoundingRect();
const rect2 = obj2.getBoundingRect();
return (
rect1.left < rect2.left + rect2.width &&
rect1.left + rect1.width > rect2.left &&
rect1.top < rect2.top + rect2.height &&
rect1.top + rect1.height > rect2.top
);
}
// Utility function to calculate the intersection area between two objects
function calculateIntersectionArea(obj1, obj2) {
const rect1 = obj1.getBoundingRect();
const rect2 = obj2.getBoundingRect();
const intersectionLeft = Math.max(rect1.left, rect2.left);
const intersectionTop = Math.max(rect1.top, rect2.top);
const intersectionWidth =
Math.min(rect1.left + rect1.width, rect2.left + rect2.width) -
intersectionLeft;
const intersectionHeight =
Math.min(rect1.top + rect1.height, rect2.top + rect2.height) -
intersectionTop;
if (intersectionWidth > 0 && intersectionHeight > 0) {
return intersectionWidth * intersectionHeight;
}
return 0;
}
let isMoving = false; // Flag to track if the object is currently being moved
// Register an event handler for object moving
canvas.on("object:moving", (event) => {
isMoving = true; // Set the flag to indicate that the object is being moved
});
// Register an event handler for object moved
canvas.on("object:moved", (event) => {
if (isMoving) {
const movedObject = event.target;
if (!movedObject.original || !movedObject.original.isBase) {
let intersectedAreas = [];
let isInArea = false;
// Iterate through all objects on the canvas
canvas.forEachObject((object) => {
// Check if the current object is an area object
if (object.original && object.original.isBase) {
// Check if the moved object intersects with the area object
if (checkIntersection(object, movedObject)) {
intersectedAreas.push({
area: object,
intersectionArea: calculateIntersectionArea(
object,
movedObject
),
});
// Check if the moved object is fully inside the area object
if (object.containsPoint(movedObject.getCenterPoint())) {
isInArea = true;
}
}
}
});
if (intersectedAreas.length > 0) {
// Sort the intersected areas based on the intersection area in descending order
intersectedAreas.sort(
(a, b) => b.intersectionArea - a.intersectionArea
);
if (!isInArea) {
// Object is not fully inside an area, snap it to the nearest area's position
const nearestArea = intersectedAreas[0].area;
movedObject.set({
left: nearestArea.left,
top: nearestArea.top,
});
// Auto-scale the moved object to fit within the nearest area
const scale = Math.min(
nearestArea.width / movedObject.width,
nearestArea.height / movedObject.height
);
movedObject.scale(scale);
}
}
}
isMoving = false; // Reset the flag once the object movement is completed
canvas.renderAll();
}
});
})();
// Extend fabric.Object.prototype to add magnet functionality to all Fabric.js objects
fabric.Object.prototype.magnetize = function (canvas) {
let isMoving = false;
// Utility function to check intersection between two objects
function checkIntersection(obj1, obj2) {
// Intersection logic here...
}
// Utility function to calculate the intersection area between two objects
function calculateIntersectionArea(obj1, obj2) {
// Intersection area calculation logic here...
}
// Method to handle object moving event
function handleMoving(event) {
isMoving = true;
}
// Method to handle object moved event
function handleMoved(event) {
if (isMoving) {
const movedObject = event.target;
if (!movedObject.original || !movedObject.original.isBase) {
let intersectedAreas = [];
let isInArea = false;
// Iterate through all objects on the canvas
canvas.forEachObject((object) => {
// Check if the current object is an area object
if (object.original && object.original.isBase) {
// Check if the moved object intersects with the area object
if (checkIntersection(object, movedObject)) {
intersectedAreas.push({
area: object,
intersectionArea: calculateIntersectionArea(
object,
movedObject
),
});
// Check if the moved object is fully inside the area object
if (object.containsPoint(movedObject.getCenterPoint())) {
isInArea = true;
}
}
}
});
if (intersectedAreas.length > 0) {
// Sort the intersected areas based on the intersection area in descending order
intersectedAreas.sort(
(a, b) => b.intersectionArea - a.intersectionArea
);
if (!isInArea) {
// Object is not fully inside an area, snap it to the nearest area's position
const nearestArea = intersectedAreas[0].area;
movedObject.set({
left: nearestArea.left,
top: nearestArea.top,
});
// Auto-scale the moved object to fit within the nearest area
const scale = Math.min(
nearestArea.width / movedObject.width,
nearestArea.height / movedObject.height
);
movedObject.scale(scale);
}
}
}
isMoving = false;
canvas.renderAll();
}
}
// Register event handlers for object moving and moved events
this.on("moving", handleMoving);
this.on("moved", handleMoved);
};
// Usage example
const canvas = new fabric.Canvas("canvas-container", {
width: 600,
height: 400,
});
const areaObject = new fabric.Rect({
width: 200,
height: 200,
fill: "transparent",
stroke: "red",
strokeWidth: 2,
selectable: false,
original: { isBase: true },
});
const regularObject = new fabric.Rect({
width: 100,
height: 100,
fill: "blue",
left: 50,
top: 50,
});
canvas.add(areaObject);
canvas.add(regularObject);
regularObject.magnetize(canvas);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment