Using fabric.js to render and manipulate server-side canvas in node.js


Question

I'm trying to use fabric.js (v0.9.21, installed via npm on ubuntu 12.04) with node.js to render a canvas on the server (which can later be manipulated and extended without clientside interaction). To experiment, I've created a simple canvas on the clientside, and then exported it to JSON using canvas.toJSON() method. When I try to reload the canvas using just that JSON, it works great (utilizing canvas.loadFromJSON()).

You can see the entire example in this fiddle.

(if it doesn't work, then the image probably expired - replace the link).

I then try to do the exact same thing on the server side using this simple script:

var fabric = require('fabric').fabric;
var fs     = require('fs');
var canvas = fabric.createCanvasForNode(570, 600);

fs.readFile('kitty.json', 'utf8', function(err, data) {
  canvas.loadFromJSON(data);
});

I get a strange crash when I run this script (using node script.js or require('./script.js') from inside node):

> http.createClient is deprecated. Use `http.request` instead.

/usr/lib/node_modules/fabric/dist/all.js:12429
      ctx.drawImage(
          ^
Error: Image given has not completed loading
    at klass.fabric.Image.fabric.util.createClass._render (/usr/lib/node_modules/fabric/dist/all.js:12429:11)
    at klass.fabric.Image.fabric.util.createClass.render (/usr/lib/node_modules/fabric/dist/all.js:12303:12)
    at klass.(anonymous function) [as render] (/usr/lib/node_modules/fabric/dist/all.js:2405:48)
    at extend._draw (/usr/lib/node_modules/fabric/dist/all.js:5332:16)
    at extend.renderAll (/usr/lib/node_modules/fabric/dist/all.js:5468:16)
    at extend.insertAt (/usr/lib/node_modules/fabric/dist/all.js:5381:37)
    at fabric.util.object.extend._enlivenObjects (/usr/lib/node_modules/fabric/dist/all.js:7694:15)
    at Array.forEach (native)
    at fabric.util.object.extend._enlivenObjects (/usr/lib/node_modules/fabric/dist/all.js:7693:24)
    at onLoaded (/usr/lib/node_modules/fabric/dist/all.js:1995:11)

The canvas has a single image in it courtesy of interwebs' kitten collection, and one text item.

I'm fairly new to node, so perhaps I've missed something along the way - any tips will be great. Thanks.

1
2
12/17/2012 4:47:37 PM

I think the issue is that you are trying to render the canvas before the image is added to the canvas. In my case calling renderAll() in the callback to loadFromJSON() solved the issue.

canvas.loadFromJSON(JSON.stringify(json),canvas.renderAll.bind(canvas));

or

canvas.loadFromJSON(JSON.stringify(json),canvas.renderAll());

This will ensure that canvas is rendered only after the json data has beed loaded into the canvas

var canvas = new fabric.Canvas('mycanvas');
var json = {
  "objects": [{
    "type": "image",
    "left": 300,
    "top": 295,
    "width": 500,
    "height": 375,
    "fill": "rgb(0,0,0)",
    "overlayFill": null,
    "stroke": null,
    "strokeWidth": 1,
    "strokeDashArray": null,
    "scaleX": 1,
    "scaleY": 1,
    "angle": 0,
    "flipX": false,
    "flipY": false,
    "opacity": 1,
    "selectable": true,
    "hasControls": true,
    "hasBorders": true,
    "hasRotatingPoint": false,
    "transparentCorners": true,
    "perPixelTargetFind": false,
    "src": "http://t3.gstatic.com/images?q=tbn:ANd9GcTE0NOJqQ46En2x1T61cZf_S4RwxOTtxcLsmfQUHkSXk5SOx-zaYnPj6jYI",
    "filters": []
  }, {
    "type": "text",
    "left": 300,
    "top": 537,
    "width": 116,
    "height": 57.6,
    "fill": "rgb(0,0,0)",
    "overlayFill": null,
    "stroke": null,
    "strokeWidth": 1,
    "strokeDashArray": null,
    "scaleX": 1,
    "scaleY": 1,
    "angle": 0,
    "flipX": false,
    "flipY": false,
    "opacity": 1,
    "selectable": true,
    "hasControls": false,
    "hasBorders": true,
    "hasRotatingPoint": false,
    "transparentCorners": true,
    "perPixelTargetFind": false,
    "text": "Kitten!",
    "fontSize": 12,
    "fontWeight": 400,
    "fontFamily": "Lato",
    "fontStyle": "",
    "lineHeight": 1.2,
    "textDecoration": "",
    "textShadow": "",
    "textAlign": "center",
    "path": null,
    "strokeStyle": "",
    "backgroundColor": "",
    "textBackgroundColor": "",
    "useNative": true
  }],
  "background": "rgba(0, 0, 0, 0)"
};
canvas.loadFromJSON(JSON.stringify(json), canvas.renderAll.bind(canvas));
#mycanvas {
  border: 1px solid black;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.1.0/fabric.all.min.js"></script>
<canvas id="mycanvas" width="570" height="600"></canvas>

0
12/21/2015 1:00:19 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon