0

After loading stickman.tojson, the circles and line rotation logic is gone.

I was able to duplicate the stickman logic to add lines to objects and the line will rotate and follow the object as I move it. I used canvas.toJSON to save the Json and all of this works fine. I can load the Json with canvas.loadFromJSON(json) and it loads fine.

The issue is after I load it, when I move the circles, the line does not follow and rotate. I tried searching for properties to include in the toJSON() but I was not able to find anything.

http://fabricjs.com/stickman/

Here is a jsfiddle sample.

    var canvas = this.__canvas = new fabric.Canvas('c', { selection: false });
  fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

saveNow = (function(){
    var jsonSave = JSON.stringify(canvas.toJSON())
   // alert(jsonSave);
    sessionStorage.canvase = jsonSave;     
});

loadNow = (function(){
    var jsonLoad = sessionStorage.canvase;
   // alert(jsonLoad);
    canvas.loadFromJSON(jsonLoad, canvas.renderAll.bind(canvas));
});

(function() {


  function makeCircle(left, top, line1, line2, line3, line4) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 5,
      radius: 12,
      fill: '#fff',
      stroke: '#666'
    });
    c.hasControls = c.hasBorders = false;

    c.line1 = line1;
    c.line2 = line2;
    c.line3 = line3;
    c.line4 = line4;

    return c;
     }

    function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
      selectable: false
    });
  }

  var line = makeLine([ 250, 125, 250, 175 ]),
      line2 = makeLine([ 250, 175, 250, 250 ]),
      line3 = makeLine([ 250, 250, 300, 350]),
      line4 = makeLine([ 250, 250, 200, 350]),
      line5 = makeLine([ 250, 175, 175, 225 ]),
      line6 = makeLine([ 250, 175, 325, 225 ]);

  canvas.add(line, line2, line3, line4, line5, line6);

  canvas.add(
    makeCircle(line.get('x1'), line.get('y1'), null, line),
    makeCircle(line.get('x2'), line.get('y2'), line, line2, line5, line6),
    makeCircle(line2.get('x2'), line2.get('y2'), line2, line3, line4),
    makeCircle(line3.get('x2'), line3.get('y2'), line3),
    makeCircle(line4.get('x2'), line4.get('y2'), line4),
    makeCircle(line5.get('x2'), line5.get('y2'), line5),
    makeCircle(line6.get('x2'), line6.get('y2'), line6)
  );

  canvas.on('object:moving', function(e) {
    var p = e.target;
    p.line1 && p.line1.set({ 'x2': p.left, 'y2': p.top });
    p.line2 && p.line2.set({ 'x1': p.left, 'y1': p.top });
    p.line3 && p.line3.set({ 'x1': p.left, 'y1': p.top });
    p.line4 && p.line4.set({ 'x1': p.left, 'y1': p.top });
    canvas.renderAll();
  });
})();

http://jsfiddle.net/pec86/28/

Steps to reproduce: 1. Move the circles objects around. 2. Click on the Save button. 3. Move the circles objects around. 4. Click on the Load button. 5. Move the circles objects around. This will now reveal what I am trying to fix/persists.

Thanks in advance.

user3067752
  • 103
  • 1
  • 8

1 Answers1

2

The problem you're facing is that canvas.toJSON() will save all the fabric's objects, as drawn in the canvas but won't save your own objects, and so it will loose the references such as the links between circles and lines.

I am no fabric.js specialist so there might be a simpler solution, however I rewrote your code so that it can accomplish what you tried to do.
I used an array to store all our lines and now the saveNow()function only saves the coordinates of those lines. I also had to rewrite the drawing function, now placed into an init() function.

Also, note that it's kind of dirty :

var canvas = this.__canvas = new fabric.Canvas('c', {
    selection: false
});
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

(function () {
    //Some other objects
    canvas.add(
        new fabric.Rect({ top: 100, left: 100, width: 50, height: 50, fill: '#f55' }),
        new fabric.Circle({ top: 140, left: 230, radius: 75, fill: 'green' }),
        new fabric.Triangle({ top: 300, left: 210, width: 100, height: 100, fill: 'blue' })
      );
    var lines,
    links = [[0,1,4,5], [1,2,3], [2], [3], [4], [5]];

    var saveNow = function () {
        //save our stickMan
        var coords = [],l;
        for (var i = 0; l = lines[i]; i++) {
            coords.push([l.x1, l.y1, l.x2, l.y2]);
        }
        sessionStorage.stickman = JSON.stringify(coords);
        //Hide our stickman
        lines.forEach(function(l){canvas.remove(l)});
        circles.forEach(function(c){canvas.remove(c)});
        //save the rest of the canvas
        sessionStorage.canvase = JSON.stringify(canvas.toJSON());
        //unhide stickman
        lines.forEach(function(l){canvas.add(l)});
        circles.forEach(function(c){canvas.add(c)});
        canvas.renderAll();
    };

    var loadNow = function () {
        var coords = JSON.parse(sessionStorage.stickman);
        canvas.clear();
        var jsonLoad = sessionStorage.canvase;
        canvas.loadFromJSON(jsonLoad, function(){canvas.renderAll.bind(canvas); init(coords);});
    };
    var btns = document.querySelectorAll('button');
    btns[0].addEventListener('click', saveNow, false);
    btns[1].addEventListener('click', loadNow, false);
    var circles;
    function makeCircle(left, top, l) {
        var c = new fabric.Circle({
            left: left,
            top: top,
            strokeWidth: 5,
            radius: 12,
            fill: '#fff',
            stroke: '#666'
        });
        c.hasControls = c.hasBorders = false;
        for (var i = 0; i < links.length; i++) {
            c["line" + i] = lines[l[i]];
        }
        circles.push(c);
        return c;
    }

    function makeLine(coords) {
        return new fabric.Line(coords, {
            fill: 'red',
            stroke: 'red',
            strokeWidth: 5,
            selectable: false
        });
    }

    function init(coords) {
        coords = coords || [
            [250, 125, 250, 175],
            [250, 175, 250, 250],
            [250, 250, 300, 350],
            [250, 250, 200, 350],
            [250, 175, 175, 225],
            [250, 175, 325, 225]
        ];
        lines = circles = [];
        var i;
        for (i = 0; i < coords.length; i++) {
            lines.push(makeLine(coords[i]));
        }
        for (i = 0; i < lines.length; i++) {
            canvas.add(lines[i]);
        }
        for (i = 0; i < lines.length; i++) {
            if (i === 0) {
                canvas.add(makeCircle(lines[i].get('x1'), lines[i].get('y1'), [null, 0]));
                canvas.add(makeCircle(lines[i].get('x2'), lines[i].get('y2'), links[i]));
            } else canvas.add(makeCircle(lines[i].get('x2'), lines[i].get('y2'), links[i]));
        }
    }
    canvas.on('object:moving', function (e) {
        var p = e.target;
        p.line0 && p.line0.set({'x2': p.left,'y2': p.top});
        p.line1 && p.line1.set({'x1': p.left,'y1': p.top});
        p.line2 && p.line2.set({'x1': p.left,'y1': p.top});
        p.line3 && p.line3.set({'x1': p.left,'y1': p.top});
        canvas.renderAll();
    });

    init();
})();

▶︎ JsFiddle

An alternative would be to subclass your objects as proposed in this answer.

Community
  • 1
  • 1
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Thanks for this answer. However, I need the load button to load the canvas.toJson and the save to create the canvas.toJson. The code I'm working on gets the Json from a server with other drawings. The code sample I provided was a cut and paste from fabricjs.com. Which one is a "custom object" in the code? – user3067752 Jun 29 '15 at 11:33
  • Well your `makeLine` and `makeCircle` function do produce custom objects. Nothing retain you to save the other objects along with those ones. But you'll have to keep the init function somewhere on your page. – Kaiido Jun 29 '15 at 12:11