It would be great if the class "object" would have SNAP and boundaries. For example you could set a snap of "25x25" and the objects will move around the canvas and snapping when the coordinate around around the next "step"
Also adding boundaries so that objects don't get pushed outside the canvas (or outside certain coordinates) would be a nice feature.
I did write some code for the boundaries that I am currently using and works, but even if I wrote some for the snapping I can't get it to stop "dancing" on the screen while resizing the object.
This is my code so far that can probably be incorporated into the object class (I am using part of someone else code, but cannot find it from where I took it):
canvas = new fabric.Canvas('canvas');
//probably those events needs to be reviewed
canvas.on('object:added', onObjectAdded);
// canvas.on('object:moving', onObjectMoving);
canvas.on('object:scaling', onObjectScaling);
// canvas.on('object:rotating', onObjectMoving);
canvas.on('object:modified', onObjectMoving);
canvas.on('after:render', onObjectMoving);
function onObjectAdded(e){
var selectedObject = e.target;
if(!selectedObject) return;
var maxWidth = canvas.getWidth()-(selectedObject.padding*2);
var maxHeight = canvas.getHeight()-(selectedObject.padding*2);
selectedObject.set({maxWidth:maxWidth,maxHeight:maxHeight});
//let's make sure we are not OUTSIDE the boundaries
//probably I should resize it in case the object is bigger than the design area
onObjectMoving(e);
}
function onObjectMoving(e){
var selectedObject = e.target;
if(!selectedObject) return;
snapToGrid(e);
var updateCoords = false,
coords = selectedObject.getBoundingRect(),
maxWidth = canvas.getWidth(),
maxHeight = canvas.getHeight();
//if the object overflow to the right/bottom reposition it
if((coords.width+coords.left)>maxWidth){
updateCoords = true;
var newLeft = (coords.width/2) + (maxWidth - coords.width);
selectedObject.set({left: newLeft});
}
if((coords.height+coords.top)>maxHeight){
updateCoords = true;
var newTop = (coords.height/2) + (maxHeight - coords.height);
selectedObject.set({top: newTop});
}
//if the object is moved "AWAY" on the left/top of the canvas reposition it
if(coords.left<0){
updateCoords = true;
selectedObject.set({left: (coords.width/2)});
}
if(selectedObject.getBoundingRect().top<0){
updateCoords = true;
selectedObject.set({top: (coords.height/2)});
}
if(updateCoords){
selectedObject.setCoords();
}
}
function snapToGrid(e){
//let's snapToGrid if necessary
if($('#snapToGrid').is(':checked')){
var selectedObject = e.target;
if(!selectedObject) return;
var updateCoords = false;
//let's get the new coords
coords = selectedObject.getBoundingRect();
//design_area['grid']['x'] //width
//design_area['grid']['y'] //height
var modX = coords.left % design_area['grid']['x'];
var modY = coords.top % design_area['grid']['y'];
if(modX!==0){
updateCoords = true;
if(modX>=(design_area['grid']['x']/2)){
var newLeft = (coords.width/2) + (coords.left + (design_area['grid']['x'] - modX));
}else{
var newLeft = (coords.width/2) + (coords.left - modX);
}
selectedObject.set({left: newLeft});
}
if(modY!==0){
updateCoords = true;
if(modY>=(design_area['grid']['y']/2)){
var newTop = (coords.height/2) + (coords.top + (design_area['grid']['y'] - modY));
}else{
var newTop = (coords.height/2) + (coords.top - modY);
}
selectedObject.set({top: newTop});
}
//weird things happen if I snap the sizing
//flickering of the box and moving of the object around
/*
//now let's snap the size
var actualWidth = selectedObject.scaleX * selectedObject.width;
var actualHeight = selectedObject.scaleY * selectedObject.height;
var modX = actualWidth % design_area['grid']['x'];
var modY = actualHeight % design_area['grid']['y'];
if(modX>0){
updateCoords = true;
if(modX>=(design_area['grid']['x']/2)){
var newX = actualWidth + (design_area['grid']['x'] - modX);
}else{
var newX = actualWidth - modX;
}
// dividing maxWidth by the shape.width gives us our 'max scale'
selectedObject.set({scaleX:newX / selectedObject.width})
}
if(modY>0){
updateCoords = true;
if(modY>=(design_area['grid']['y']/2)){
var newY = actualHeight + (design_area['grid']['y'] - modY);
}else{
var newY = actualHeight - modY;
}
selectedObject.set({scaleY:newY / selectedObject.height})
}
*/
}
if(updateCoords){
selectedObject.setCoords();
onObjectScaling(e);
}
}
function onObjectScaling(e){
var shape = e.target,
maxWidth = shape.get("maxWidth"),
maxHeight = shape.get("maxHeight"),
actualWidth = shape.scaleX * shape.width,
actualHeight = shape.scaleY * shape.height;
if(!isNaN(maxWidth) && actualWidth >= maxWidth){
// dividing maxWidth by the shape.width gives us our 'max scale'
shape.set({scaleX:maxWidth / shape.width});
}
if(!isNaN(maxHeight) && actualHeight >= maxHeight){
shape.set({scaleY:maxHeight / shape.height});
}
};
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
Thanks for your suggestion! I think this is out of scope for Fabric at the moment, but I'll mark this as possible feature.
Would it be ok if I figure out a way to implement in the object class, I believe that the boundaries might be very easy to implement ?
I am VERY new to github so i won't know how to post a possible revision. but I am willing to try
Sure. Although a mixin might be better. Snapping could be easily done on an application-level. Just whipped this demo — http://jsfiddle.net/fabricjs/S9sLu/ Snapping code is exactly 4 lines :)
Moving snapping yes, resizing snapping I assume it is a different story,
but then I tried only when I was VERY new to fabric. Will look again
into it.
Here is another try: http://jsfiddle.net/squeral/m4rYZ/
Here is snapping on scaling an object: http://jsfiddle.net/squeral/9tB8n/
Needs a bit of clean up but it works.
I combined your jsfiddles, snap on move & resize demo:
http://jsfiddle.net/9tB8n/15/
Hey, here is compilation of boundaries and scale\move snapping to grid: http://jsfiddle.net/9tB8n/20/
There's one problem that I struggle to solve. That is if you scale outside of boudaries - the object get's scales on the opposite side. Can someone explain what is going on?
Is it possible snap to other objects?
@evolutionjay
it's possible to snap to any object on the canvas:
http://jsfiddle.net/fabricjs/S9sLu/
https://stackoverflow.com/questions/22591927/snap-edges-of-objects-to-each-other-and-prevent-overlap
You just have to search a bit and adapt the solutions available to your exact needs.
Good luck,
Alex
Most helpful comment
Hey, here is compilation of boundaries and scale\move snapping to grid: http://jsfiddle.net/9tB8n/20/
There's one problem that I struggle to solve. That is if you scale outside of boudaries - the object get's scales on the opposite side. Can someone explain what is going on?