Glory to Russia
Glory to Russia

Reputation: 18712

How to set the background image of FabricJS canvas to image from a web service?

I have following piece of code, which is executed when the user presses a button. It

  1. connects to a web service,
  2. gets an image from it,
  3. stores it in myDataURL variable and
  4. displays it on the canvas.

Here's the code:

function downloadButtonPressed() {
    var username = $("input#username").val();
    var password = $("input#password").val();
    $.ajax({
        type: "GET",
        url: "http://myserver/myapp/map",
        headers: {
            "Authorization": "Basic " + btoa(username + ":" + password),
          },
        crossDomain: true,
        xhrFields: {
                withCredentials: true
            },
        success: function (data, status, xhr) {
            alert("success");
        }
    }).fail(function ($xhr) {
        console.log("response: " + $xhr);
        var myDataURL = "data:image/png;base64," + $xhr.responseText;
        var canvas = document.getElementById('canvas');
        var context = canvas.getContext('2d');
        var img = new Image();
        img.onload = function() {
            context.drawImage(this, 0, 0, canvas.width, canvas.height);
        };
        img.src = myDataURL;
    });
}

And here's what the browser window looks like, after I press the download button:

Screenshot

Now I want to make that image a backgrond image of the canvas, so that I can add other objects (e. g. rectagles, other images) on top of it.

How can I do it?

The official FabricJS tutorial recommends this:

var myDataURL = "data:image/png;base64," + $xhr.responseText;
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
    // context.drawImage(this, 0, 0, canvas.width, canvas.height);
};
img.src = myDataURL;
canvas.setBackgroundImage(myDataURL, canvas.renderAll.bind(canvas));

But then I get the following error:

Screenshot

Update 1 (02.12.2015 13:23 MSK): Regardless of which method I use, the background image disappears as soon as I click on it after download.

Here is a video, which shows, what I mean.

Update 2 (02.12.2015 13:28 MSK):

Here's the current version of code:

Option 1:

function ($xhr) {
    var myDataURL = "data:image/png;base64," + $xhr;
    var canvas = new fabric.Canvas('canvas');
    var img = new Image();
    img.onload = function() {
        var f_img = new fabric.Image(img);
        canvas.setBackgroundImage(f_img);
        canvas.renderAll();
    };
    img.src = myDataURL;
}

Option 2:

function ($xhr) {
    var myDataURL = "data:image/png;base64," + $xhr;
    var canvas = new fabric.Canvas('canvas');
    canvas.setBackgroundImage(myDataURL, canvas.renderAll.bind(canvas));
}

Update 3 (02.12.2015 14:07 MSK):

Same problem occurs, if I try to add a rectangle to the canvas using the following code.

function rectButtonPressed() {
    var canvas = new fabric.Canvas('canvas');
    var rect = new fabric.Rect({
      left: 100,
      top: 100,
      fill: 'red',
      width: 20,
      height: 20
    });
    canvas.add(rect);
}

First, it appears, but when I click on the canvas, it becomes empty again.

Upvotes: 2

Views: 10971

Answers (1)

AndreaBogazzi
AndreaBogazzi

Reputation: 14731

Main problem of your code is that you are working with the canvas element and not the fabricJS canvas.

To use canvas.renderAll() function you have to initialize a fabric.Canvas object.

Check the snippet:

var myDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAYAAACAvzbMAAAKkklEQVR4nO3dMW4cRxqGYfWaoZOFADnYRMAm4gGcSKkV2KDCPcFeYQGHS0eG4TPsBTY1YQZySiV7AAqOlDiQAMGJU6E3tERB9WO+YrF6Zp4nE1rT3TND80Vp5nct67qu9wBgR3+ZfQMA7CcBASAiIABEBASAiIAAEBEQACICAkBEQACICAgAEQEBICIgAEQEBICIgAAQERAAIgICQORk9g3AUMsy9vy20+GIWYEAEBEQACICAkBEQACICAgAEQEBICIgAESWdfVFdo7X8l37+HpujgQ+xQoEgIiAABAREAAiAgJAREAAiAgIABEBASBiPxAO2tK5H0jvFIgxKw6ZFQgAEQEBICIgAEQEBICIgAAQERAAIgICQMQcCFNdvHg59PzlHMYvxYYghde//9E8Xj2/s8ePuq4/+vWr9N4/+80KBICIgAAQERAAIgICQERAAIgICAARAQEgsqw2LGCiy2K/jndX10Ov/+Vv/+l6/P/+9s/m8bMnp83jl8X5q+d/+vBB8/j1qzfN48+K+6v49XHcrEAAiAgIABEBASAiIABEBASAiIAAEBEQACLmQJiqmgOpVHMS1RxG5aLz/NWcR6/q+X/W+fy/KY779XHcrEAAiAgIABEBASAiIABEBASAiIAAEBEQACIns2+A/VbNcXzdef7q8ZfFnMPr//6refyLv37ePF7NUVRzHr3Pvzp/75xHdX8/d52dQ2cFAkBEQACICAgAEQEBICIgAEQEBICIgAAQMQfCVL1zEr1e//5H8/jXz8/bJ3haHC+MniPpvr79PmiwAgEgIiAARAQEgIiAABAREAAiAgJAREAAiCzr6ovefFq130evcr+PzsdXLq6um8dPHz5oHr9+9aZ5/Gzj+4mU5/frgQYrEAAiAgJAREAAiAgIABEBASAiIABEBASAiDkQmi5evOx6/GfFHESl2o9i9JzKu8FzIr2vT8WcByNZgQAQERAAIgICQERAAIgICAARAQEgIiAARE5m3wD7rZyDKOYozh4/6rp+NSdyr5gTqfbLePa8fX8/PW3PyVSvz9+L61eq+zfnwUhWIABEBASAiIAAEBEQACICAkBEQACICAgAEXMgdPn86vvm8bN//HhHd5Kp9sv4+bw9R/LNvfacRfX4X4vrV8o5GBjICgSAiIAAEBEQACICAkBEQACICAgAEQEBILKsqy+SH7Vfvpt7/a/+PfT0S7EfSGV9fn47N/IJy9O+8/vPl5msQACICAgAEQEBICIgAEQEBICIgAAQERAAIuZA2LTLzjmOXtV+Ict5334g1fkvi+P2A2EmKxAAIgICQERAAIgICAARAQEgIiAARAQEgIg5EIba+hxHpZrzWIs5j0o159HLnAgjWYEAEBEQACICAkBEQACICAgAEQEBICIgAETMgdBn8pxHZfScxWi9cyz2E2EkKxAAIgICQERAAIgICAARAQEgIiAARAQEgIg5EPoUcyDlHELn5Wfvp1Htd1I9v977NyfCTFYgAEQEBICIgAAQERAAIgICQERAAIgICAARcyA0VXMOld45hV6z5xx650Rmm/36sW1WIABEBASAiIAAEBEQACICAkBEQACICAgAkZPZN8BcFy9etv/C1XXfBZ6cNg/37hey9TmFre8n8q73/eWoWYEAEBEQACICAkBEQACICAgAEQEBICIgAETMgdB0+vBB8/j1qzfN471zCveKOYqt76dR6Z5T6dyvpVK9/9Uc0dnjR7d5O2yMFQgAEQEBICIgAEQEBICIgAAQERAAIgICQGRZ18kbJjBU9T393jmPZ8V+H368tq3cD6bQ+/NjTmS/WYEAEBEQACICAkBEQACICAgAEQEBICIgAETMgey52XMeFT9e27YU+4n8dHXddX5zIofNCgSAiIAAEBEQACICAkBEQACICAgAEQEBIHIy+wYYy5wHLdX71zsnUv38sd+sQACICAgAEQEBICIgAEQEBICIgAAQERAAIuZADpw5D3qMnhNhv1mBABAREAAiAgJAREAAiAgIABEBASAiIABEzIFs3MWLl83j5jyYyZzIcbMCASAiIABEBASAiIAAEBEQACICAkBEQACImAOZrJrzOH34oOv85jyYqZrzqH6+qzkSP99zWYEAEBEQACICAkBEQACICAgAEQEBICIgAETMgQxWfY999vV9j56Rzh4/ah6v5qDYNisQACICAkBEQACICAgAEQEBICIgAEQEBIDIshoEACYZPSfl19tYViAARAQEgIiAABAREAAiAgJAREAAiAgIABH7gQDTmNPYb1YgAEQEBICIgAAQERAAIgICQERAAIgICAARAQEgIiAARAQEgIiAABAREAAiAgJAREAAiAgIABEBASAiIABEBASAiIAAEBEQACICAkBEQACICAgAEQEBICIgAEQEBICIgAAQOZl9A9ytZVlm38JRW9e1eXzf35/q+XFYrEAAiAgIABEBASDiM5Aj9/btk6Hnv3//auj1t37+6vGV3vPPfjyHzQoEgIiAABAREAAiPgOBO7Tvcx7wPisQACICAkBEQACI+AzkyG19DmDfzz/79YORrEAAiAgIABEBASDiM5AjM3o/ikPf7wL4kxUIABEBASAiIABEltUmxrzn5mcU67fF3//hwz/v+hlIdf7KzevfNPv8s++v0nv/H53Pr5OjYgUCQERAAIgICAARcyBwQGbP+XBcrEAAiAgIABEBASBiDoQPfDSnUf39G3/eeQ5kx/Pv6tjOP/r19+uC91mBABAREAAiAgJAxBwI3CH7pXBIrEAAiAgIABEBASDiMxA2bWtzFsCfrEAAiAgIABEBASAiIABEBASAiIAAEBEQACLmQGgaPQfh/Id9fg6bFQgAEQEBICIgAETsiQ5AxAoEgIiAABAREAAiAgJAREAAiAgIABEBASDi/4XVaVn2+/8mVI0BjX5+s6/PWL1jZrN//mizAgEgIiAARAQEgIjPQG7Z27dPhp7//v2rrutXj6/0Pr/R1x/9+mz9/d36+Xtt/f6OjRUIABEBASAiIABEfAZy5MxZMJKfr8NmBQJAREAAiAgIABGfgdyxrX8PffQcyb6bPYdTmX3+2XM63C0rEAAiAgJAREAAiPgMZOMOfb+Mrd//6Nf/0N9fDpsVCAARAQEgIiAARJbVpsBdbv4b9fpt5/l++PDPu/4beXX9m+e/afTjK6PPv+v1R7/+t33+yuz3r7K195c2KxAAIgICQERAAIgICAARAQEgIiAARAQEgIg5kE4ffU+/+vs7nn/nOYFbvv5H99P5+NHXr86/6+NHv/779v7e9ut722779afNCgSAiIAAEBEQACL2A5ls9r/Bzt6PYvb1gZwVCAARAQEgIiAARHwGwk565wAYa/YcRq/Zc0bsxgoEgIiAABAREAAiPgOhyZwG+2z2nNWhswIBICIgAEQEBICIz0Bu2exPBA79+r3n3/r97fv5Zz+eu2UFAkBEQACICAgAEXuiAxCxAgEgIiAARAQEgIiAABAREAAiAgJAREAAiAgIABEBASAiIABEBASAiIAAEBEQACICAkBEQACICAgAEQEBICIgAEQEBICIgAAQERAAIgICQERAAIgICAARAQEgIiAARAQEgMj/ARYVSURm9DRHAAAAAElFTkSuQmCC";

var canvas = new fabric.Canvas('canvas');
var img = new Image();
img.onload = function() {
    // this is syncronous
    var f_img = new fabric.Image(img);
    canvas.setBackgroundImage(f_img);
    canvas.renderAll();
};
img.src = myDataURL;
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id='canvas' width="400" height="400" style="border:#000 1px solid;"></canvas>

Also if you do not need the img element for some reason, you can just do as you stated before:

var canvas = new fabric.Canvas('canvas');
canvas.setBackgroundImage(myDataUrl, canvas.renderAll.bind(canvas));

That is shorter and nicer.

Upvotes: 7

Related Questions