Snapping object to grid
by Hooman Askari
HTML
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
CSS
canvas {
border: 1px solid #ccc;
}
JavaScript
// Build using FabricJS v3.4
var canvas = new fabric.Canvas('c', {
selection: false
});
var snapSize = 10;
var gridSize = 10;
// create grid
for (var i = 0; i < (600 / gridSize); i++) {
canvas.add(new fabric.Line([i * gridSize, 0, i * gridSize, 600], {
stroke: '#ccc',
selectable: false
}));
canvas.add(new fabric.Line([0, i * gridSize, 600, i * gridSize], {
stroke: '#ccc',
selectable: false
}))
}
// add objects
canvas.add(new fabric.Rect({
left: 100,
top: 100,
width: 50,
height: 50,
fill: '#faa',
originX: 'left',
originY: 'top',
centeredRotation: true
}));
canvas.add(new fabric.Circle({
left: 300,
top: 300,
radius: 50,
fill: '#9f9',
originX: 'left',
originY: 'top',
centeredRotation: true
}));
function Snap(value) {
return Math.round(value / snapSize) * snapSize;
}
function SnapMoving(options) {
options.target.set({
left: Snap(options.target.left),
top: Snap(options.target.top)
});
}
function SnapScaling(event) {
const {
transform
} = event;
const {
target
} = transform;
const targetWidth = target.width * target.scaleX;
const targetHeight = target.height * target.scaleY;
const snap = {
// closest width to snap to
width: Snap(targetWidth),
height: Snap(targetHeight),
};
const threshold = gridSize;
const dist = {
// distance from current width to snappable width
width: Math.abs(targetWidth - snap.width),
height: Math.abs(targetHeight - snap.height),
};
const centerPoint = target.getCenterPoint();
const anchorY = transform.originY;
const anchorX = transform.originX;
const anchorPoint = target.translateToOriginPoint(
centerPoint,
anchorX,
anchorY,
);
const attrs = {
scaleX: target.scaleX,
scaleY: target.scaleY,
};
// eslint-disable-next-line default-case
switch (transform.corner) {
case 'tl':
case 'br':
case 'tr':
case 'bl':
if (dist.width < threshold) {
...