A. L
A. L

Reputation: 12679

Fabricjs - How to detect total width/height of canvas where objects exist

So I want to save the canvas based on scale 1 and I want to include all existing/visible objects.

So right now, my canvas is 600x400 and if I were to save it, it would only save what's inside that 600x400, and it respects zoom level (a higher zoom will see less things, a lower zoom will see more things but smaller).

I've gotten around this by running this code:

let zoom = this.canvas.getZoom();
this.canvas.setZoom(1);
let url = this.canvas.toDataURL({width: 1000, height: 700, multiplier: 1});
this.canvas.setZoom(zoom);
window.open(
  url,
  '_blank' // <- This is what makes it open in a new window.
);

What this does is save the image as 1000x700, so stuff that were past 600px but under 1000 still gets saved.

However, this is hard coded. So I was wondering if there was an existing function or a clean/simple way to detect where all the objects are in and returns the full size (width and height).


fiddle: http://jsfiddle.net/1pxceaLj/3/

Update 1:

var gr = new this.fabric.Group([], {
  left: 0,
  top: 0
});
this.canvas.forEachObject( (o) => {
  gr.add(o);
});

this.canvas.add(gr);
this.canvas.renderAll();

console.log(gr.height, gr.width); // 0 0

Solution

Using group was the best idea. Best example: http://jsfiddle.net/softvar/mRA8Z/

function selectAllCanvasObjects(){
    var objs = canvas.getObjects().map(function(o) {
        return o.set('active', true);
    });

    var group = new fabric.Group(objs, {
        originX: 'center', 
        originY: 'center'
    });

    canvas._activeObject = null;

    canvas.setActiveGroup(group.setCoords()).renderAll();
    console.log(canvas.getActiveGroup().height);
}

Upvotes: 1

Views: 1772

Answers (1)

Dominik
Dominik

Reputation: 2906

One possibility would be to create a kind of Container using a fabricjs group and adding all created objects to this container.

I updated your fiddle here: http://jsfiddle.net/1pxceaLj/4/

Thus, you could just use group.width and group.height, perhaps adding a little offset or minimum values, and there you are having dynamical value to pass into toDataUrl even when having a smaller canvas.

code:

var canvas  = new fabric.Canvas('c');

var shadow = {
    color: 'rgba(0,0,0,0.6)',
    blur: 20,    
    offsetX: 10,
    offsetY: 10,
    opacity: 0.6,
    fillShadow: true, 
    strokeShadow: true 
}

 var rect = new fabric.Rect({
        left: 100,
        top: 100,
        fill:  "#FF0000",
        stroke: "#000",
        width: 100,
        height: 100,
        strokeWidth: 10, 
        opacity: .8      
    });

 var rect2 = new fabric.Rect({
        left: 800,
        top: 100,
        fill:  "#FF0000",
        stroke: "#000",
        width: 100,
        height: 100,
        strokeWidth: 10, 
        opacity: .8      
    });    
rect.setShadow(shadow);
//canvas.add(rect);
//canvas.add(rect2);

var gr = new fabric.Group([ rect, rect2 ], {
  left: 0,
  top: 0
});

canvas.add(gr);

function save()
{
        alert(gr.width);
    alert(gr.height);
    let zoom = canvas.getZoom();
    var minheight = 700;
    canvas.setZoom(1);
    let url = this.canvas.toDataURL({width: gr.width, height: gr.height > minheight ? gr.height : minheight, multiplier: 1});
    canvas.setZoom(zoom);
    window.open(
      url,
      '_blank'
    );  
}

Upvotes: 2

Related Questions