4

I'm using fabricjs (1.7.20) and would like to create a sort of "bleed area" where some space around the canvas isn't usable by the user; a sort of "wall" if you will, to stop objects from being moved to the sides of the canvas walls. How might I accomplish this?

var canvas = new fabric.Canvas("c");
canvas.setHeight(350);
canvas.setWidth(350);

canvas.add(new fabric.IText("Some text", {
  top: 25,
}));

var circle = new fabric.Circle({
  radius: 20, fill: 'green', left: 100, top: 100
});
var triangle = new fabric.Triangle({
  width: 20, height: 30, fill: 'blue', left: 150, top: 150
});

canvas.add(circle, triangle);
canvas {
  border: 1px solid #dddddd;
  margin-top: 10px;
  border-radius: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js"></script>
<canvas id="c"></canvas>

This was suggested to me and it is the closest I've gotten. I'm looking to do this, but 10px, give or take, from the border of the canvas.

canvas.on('object:moving', function (e) {
        var obj = e.target;
         // if object is too big ignore
        if(obj.currentHeight > obj.canvas.height || obj.currentWidth > obj.canvas.width){
            return;
        }        
        obj.setCoords();        
        // top-left  corner
        if(obj.getBoundingRect().top < 0 || obj.getBoundingRect().left < 0){
            obj.top = Math.max(obj.top, obj.top-obj.getBoundingRect().top);
            obj.left = Math.max(obj.left, obj.left-obj.getBoundingRect().left);
        }
        // bot-right corner
        if(obj.getBoundingRect().top+obj.getBoundingRect().height  > obj.canvas.height || obj.getBoundingRect().left+obj.getBoundingRect().width  > obj.canvas.width){
            obj.top = Math.min(obj.top, obj.canvas.height-obj.getBoundingRect().height+obj.top-obj.getBoundingRect().top);
            obj.left = Math.min(obj.left, obj.canvas.width-obj.getBoundingRect().width+obj.left-obj.getBoundingRect().left);
        }
});
anonymoose
  • 1,169
  • 2
  • 21
  • 62
  • Possible duplicate of [Move object within canvas boundary limit](https://stackoverflow.com/questions/22910496/move-object-within-canvas-boundary-limit) – Patrick Hund Dec 18 '17 at 21:15
  • 1
    I checked that out. With it I was able to top objects from going outside of the canvas but I'm wondering how to, more specifically, keep them from ~10 pixels from the canvas. – anonymoose Dec 26 '17 at 18:23

1 Answers1

3

You can add a 10 pixel bleed area by adding / subtracting the value 10 from the conditions that determine if an object is being moved out of the “bleed” area (I'd actually prefer to call it “padding”), and adding / subtracting from the calculation that repositions the object inside the padding boundaries.

Here's an updated example that works:

var padding = 10;
var canvas = new fabric.Canvas("c");

canvas.setHeight(350);
canvas.setWidth(350);

canvas.add(new fabric.IText("Some text", {
    top: 25,
}));

var circle = new fabric.Circle({
    radius: 20,
    fill: 'green',
    left: 100,
    top: 100
});
var triangle = new fabric.Triangle({
    width: 20,
    height: 30,
    fill: 'blue',
    left: 150,
    top: 150
});

canvas.add(circle, triangle);

canvas.on('object:moving', function(e) {
    var obj = e.target;
    
    // if object is too big ignore
    if (obj.currentHeight > obj.canvas.height - padding * 2 ||
        obj.currentWidth > obj.canvas.width - padding * 2) {
        return;
    }
    obj.setCoords();

    // top-left corner
    if (obj.getBoundingRect().top < padding ||
     obj.getBoundingRect().left < padding) {
        obj.top = Math.max(obj.top, obj.top - obj.getBoundingRect().top + padding);
        obj.left = Math.max(obj.left, obj.left - obj.getBoundingRect().left + padding);
    }
    
    // bot-right corner
    if (obj.getBoundingRect().top + obj.getBoundingRect().height > obj.canvas.height - padding || 
     obj.getBoundingRect().left + obj.getBoundingRect().width > obj.canvas.width - padding) {
        obj.top = Math.min(
         obj.top,
         obj.canvas.height - obj.getBoundingRect().height + obj.top - obj.getBoundingRect().top - padding);
        obj.left = Math.min(
         obj.left,
            obj.canvas.width - obj.getBoundingRect().width + obj.left - obj.getBoundingRect().left - padding);
    }
});
canvas {
  border: 1px solid #dddddd;
  margin-top: 10px;
  border-radius: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js"></script>
<canvas id="c"></canvas>

In the first line, I've defined a variable “padding” that refers to the desired padding size. This way, if you want to change the padding later on, you don't have to change it in eight different places.

The padding variable used instead of 0 in the condition for the top left corner.

If the “top left” condition is true, the padding is added to the calculation for repositioning the object.

In the “bottom right” part, we are doing the opposite – we subtract the padding from the condition and subtract from the repositioning calculation.

You can also try the code in this fiddle: https://jsfiddle.net/pahund/hz7jLnme/

Patrick Hund
  • 19,163
  • 11
  • 66
  • 95
  • 2
    Beautiful. Thank you! This is correct and I'll award the bounty as soon as it'll let me (21 hours). On this vein, would it be rough to restrict drawing on the canvas to say, that ten pixels but on the lower half of the canvas (in other words, maybe a 330 * 116px * box? I can ask another question if need be! Cheers! – anonymoose Dec 26 '17 at 21:22
  • 2
    Glad to help ! Well, you don't have to use that padding variable, you can simple edit the places where I'm using it to do your own thing. I suggest you do some experimenting with the fiddle, see how it works, and if you can't make it do what you want, post another question. – Patrick Hund Dec 26 '17 at 21:26
  • Hi @PatrickHund Is it possible to even create clippath offset that should restrict the objects? Preventing inside move event is fine but it would be good if we can see the path with dotted line to indicate where it;s gonna stop. Kind of offsetpath in illustrator. – Shashank Bhatt Jun 02 '23 at 05:16