Link to home
Start Free TrialLog in
Avatar of Ivan Golubar
Ivan Golubar

asked on

Save particular elements parameters to Jason

Next code is from one demo from fabric.js http://fabricjs.com/stickman
It assigns lines to circle, so then when circle is moved assigned lines are following it.

 var circle1=[];
  function makeCircle(left, top, line1, line2) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 2,
      radius: 6,
      fill: '#fff',
      stroke: '#666',
      name:'polyline'
    });
    c.hasControls = c.hasBorders = false;

    c.line1 = line1;
    c.line2 = line2;
    return c;
  }

Open in new window



 var leftx2,topy2;
var moveHandler = function (evt) {
    var obj = evt.target;
  leftx2 = obj.get('left');
  topy2 = obj.get('top');
   //console.log(leftx2);
  //console.log(topy2);
    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });
  }

Open in new window


I need to save  elements data  to DB, so I am using JSON for it.
It works fine  to  save all parameters ( i get elements after page refresh) , but not the information which lines will move, if circle is moving.
How to save also this?

I was trying to add line1,line2 to:
function saveJsonF(){ //____________________________________________________________________saveJsonF; 
var jsonToPHP= JSON.stringify(canvas.toObject(['id','name','line1','line2']));

Open in new window


But is not working.
How to find out as which parameter is  'line1','line2' ?
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Where is this defined
canvas.toObject

Open in new window

Avatar of Ivan Golubar
Ivan Golubar

ASKER

Next is  from:
http://fabricjs.com/docs/fabric.Canvas.html


toObject(propertiesToIncludeopt) → {Object}
Returns object representation of canvas
Parameters:
Name      Type      Attributes      Description
propertiesToInclude      Array      <optional>
Any properties that you might want to additionally include in the output
Inherited From:
fabric.StaticCanvas#toObject
Source:
fabric.js, line 7441
Returns:
object representation of an instance
Type
Object
What is the result of this line
var jsonToPHP= JSON.stringify(canvas.toObject(['id','name','line1','line2']));

Open in new window

If you console.log() that out what do you get?
{"objects":[{"type":"circle","originX":"center","originY":"center","left":115,"top":116,"width":12,"height":12,"fill":"#fff","stroke":"#666","strokeWidth":2,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"radius":6,"startAngle":0,"endAngle":6.283185307179586,"name":"polyline","line1":null,"line2":{"type":"line","originX":"center","originY":"center","left":446.5,"top":237.5,"width":663,"height":243,"fill":"red","stroke":"red","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"x1":-331.5,"x2":331.5,"y1":-121.5,"y2":121.5}},{"type":"line","originX":"center","originY":"center","left":446.5,"top":237.5,"width":663,"height":243,"fill":"red","stroke":"red","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"name":"polyline","x1":-331.5,"x2":331.5,"y1":-121.5,"y2":121.5},{"type":"circle","originX":"center","originY":"center","left":778,"top":359,"width":12,"height":12,"fill":"#fff","stroke":"#666","strokeWidth":2,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"radius":6,"startAngle":0,"endAngle":6.283185307179586,"name":"polyline","line1":{"type":"line","originX":"center","originY":"center","left":446.5,"top":237.5,"width":663,"height":243,"fill":"red","stroke":"red","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"x1":-331.5,"x2":331.5,"y1":-121.5,"y2":121.5},"line2":null}]}
According to fabric example the canvas element has an _object property that contains the coordinates of lines and circles:
User generated imageUser generated imageAt this example code I added a save button that push the line1(head of sticky man) properties into cooRdinates array:
  <!DOCTYPE html>
<html lang="en" ng-app="kitchensink">
  <head>
    <meta charset="utf-8">

    <title>Stickman | Fabric.js Demos</title>
    
    <link rel="stylesheet" href="http://fabricjs.com/css/master.css">
    <link rel="stylesheet" href="http://fabricjs.com/css/ads.css">
    <link rel="stylesheet" href="http://fabricjs.com/css/prism.css">
   
    <script src="http://fabricjs.com/lib/fabric.js"></script>

    
  </head>
  <body>
    <ul id="header">  
  <li class="github secondary">
    <iframe src="http://ghbtns.com/github-btn.html?user=kangax&repo=fabric.js&type=watch&count=true"
      allowtransparency="true" frameborder="0" scrolling="0" width="95px" height="20px"></iframe>
  </li>
  <li class="twitter secondary">
    <a href="https://twitter.com/fabricjs" class="twitter-follow-button" data-show-count="true">Follow @fabricjs</a>
  </li>
  <li id="carbonads-container">
    <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=fabricjscom" id="_carbonads_js"></script>
  </li>
</ul>




    <div id="bd-wrapper" ng-controller="CanvasControls">
      <h2><span>Fabric.js demos</span> &middot; Stickman</h2>

      <canvas id="c" width="500" height="500" style="border:1px solid #ccc"></canvas>
	  <button id="save">Save</button>
<script>
 (function() {
 var cooRdinates=[];
  var canvas = this.__canvas = new fabric.Canvas('c', { selection: false });
  fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

  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();
  });
  document.getElementById('save').addEventListener('click',function(){
    console.log(canvas);
	cooRdinates.push(JSON.stringify(canvas._objects[0]));
	console.log(cooRdinates);
  })
})();
</script>


  </body>
</html>

Open in new window

The result after 3 click saves is that (notice that the second and third click made without any movement of the sticky mans head):
User generated imageUser generated imageSo...I think that you must save (at database) and replace at canvas._object property (after initialization) only the parameters that changed ie:
User generated imageUser generated image
ASKER CERTIFIED SOLUTION
Avatar of Leonidas Dosas
Leonidas Dosas
Flag of Greece image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Can you show us what is not working. You have valid JSON - what is it you are expecting to see that you are not.
That is the problem: i don't know  what i must see.

Or why if i save objects from canvas with :
var jsonToPHP= JSON.stringify(canvas.toObject(['id','name','line1','line2']));

Open in new window


and then retrieve  on refresh with:
  canvas.loadFromJSON(strdate, function() {   
     canvas.renderAll();    
      });

Open in new window


next will not work as it was before closing of page:
 var leftx2,topy2;
var moveHandler = function (evt) {
    var obj = evt.target;
  leftx2 = obj.get('left');
  topy2 = obj.get('top');
   //console.log(leftx2);
  //console.log(topy2);
    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });  
}

Open in new window

Let me put together all my code and to attach it here. It will be in minutes.
Next code is  adaptation of demo (link at beginning of this post) from fabric.js.  Check for direct link for  fabric.js library  online, because i did downloaded it to my server and i am running from there.

On each click you are adding line and circle for anchor point at end of the line.

To recapitulate. I do get all objects on canvas as they were before saving. But i lose  movement of lines behind the circle when circle is moving.



<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
 <script src="/wp-content/themes/4/js/fabric.min.js"></script>
<style>

</style>

<script>
var canvas = new fabric.Canvas('c');  
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

var line1=[];
 function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
    selectable: false,
     name:'polyline'
    });
 }
 var circle1=[];
  function makeCircle(left, top, line1, line2) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 2,
      radius: 6,
      fill: '#fff',
      stroke: '#666',
      name:'polyline'
    });
    c.hasControls = c.hasBorders = false;

    c.line1 = line1;
    c.line2 = line2;

    return c;
  }
 

var lineCount=0;
var posX1=0;
var posY1=0;
var posX2=0;
var posY2=0;
function drawPoly(){
      
       if (lineCount!=0){
       line1[lineCount] = makeLine([posX1, posY1, posX2, posY2 ]);
       canvas.add(line1[lineCount]);
        console.log(line1[lineCount].type,line1[lineCount].name);
       } 

     if (lineCount==0){
          circle1[lineCount]=makeCircle( posX2, posY2, null,null);
          canvas.add(circle1[lineCount]); 
      }
      if (lineCount>0){
         circle1[lineCount]= makeCircle(line1[lineCount].get('x2'), line1[lineCount].get('y2'), line1[lineCount],null);
         canvas.add(circle1[lineCount]); 
         circle1[lineCount-1].line2 =line1[lineCount];
      } 
      
     lineCount=lineCount+1;    
}

canvas.on('mouse:down', function(e) {
    var obj2 = e.target;
    if (obj2!= null){console.log(obj2.type);}
   
  if (obj2==null){
         posX1 = posX2;
         posY1 = posY2;
         var pointer = canvas.getPointer(e.e);
         posX2 = pointer.x;
         posY2 = pointer.y;
         drawPoly();
      }else{lineCount=0;}
} 

 var leftx2,topy2;
var moveHandler = function (evt) {
    var obj = evt.target;
  leftx2 = obj.get('left');
  topy2 = obj.get('top');
   //console.log(leftx2);
  //console.log(topy2);
    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });
}

</script>
</head>
<body>
       <canvas  id="c" width="1060" height="550"  > 

 
</div>
</body></html>

Open in new window

Can't see where in your script you are doing the save / restore?
It is part of another *.js.

Its:
function getJsonF(){ ////////////////////////////////////                              JSgetjson
$.ajax({
  method:"POST",
  url: '/wp-content/themes/4/PgetJson.php',
  data:  {
    "getCanvas":1,
    "whichProject":whichProjectToSave,
    },
    datatype: "text",
    success: function(strdate){
   console.log("getJsonF; "+strdate);
 
   canvas.loadFromJSON(strdate, function() {
     canvas.renderAll();
       
      });
     },
     error: function(error, txtStatus) {
      console.log(txtStatus);
      console.log('error');
    }
 });
}

Open in new window


And:
function saveJsonF(){ //____________________________________________________________________saveJsonF; 
var jsonToPHP= JSON.stringify(canvas.toObject(['id','name','line1','line2']));
//var jsonToPHP= JSON.stringify(canvas.toObject(['id','name']));
console.log("saveJsonF: "+jsonToPHP);
$.ajax({
  method:"POST",
  url: '/wp-content/themes/4/PsaveJson.php',
  data: {
    "sendCanvas":1,
    "whichProjectToSave":whichProjectToSave,
    "jsonToPHP": jsonToPHP
  },
  success: function(data){
      console.log(whichProjectToSave+"ok1 saveJsonF");
  },
     error: function(error, txtStatus) {
      console.log(txtStatus+"saveJsonF");
      console.log('error');
    }
}); 
}

Open in new window

Do you mean something like this?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="http://fabricjs.com/lib/fabric.js"></script>
<style>

</style>


</head>
<body>
       <canvas  id="c" width="1060" height="550"  > 

 
</div>
<script>
var canvas = new fabric.Canvas('c');  
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
 var leftx2,topy2;
var moveHandler = function (evt) {
    var obj = evt.target;
  leftx2 = obj.get('left');
  topy2 = obj.get('top');
   //console.log(leftx2);
  //console.log(topy2);
    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });
	
}


var line1=[];
 function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
    selectable: false,
     name:'polyline'
    });
 }
 var circle1=[];
  function makeCircle(left, top, line1, line2) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 2,
      radius: 6,
      fill: '#fff',
      stroke: '#666',
      name:'polyline'
    });
    c.hasControls = c.hasBorders = false;

    c.line1 = line1;
    c.line2 = line2;

    return c;
  }
 

var lineCount=0;
var posX1=0;
var posY1=0;
var posX2=0;
var posY2=0;
function drawPoly(){
      
       if (lineCount!=0){
       line1[lineCount] = makeLine([posX1, posY1, posX2, posY2 ]);
       canvas.add(line1[lineCount]);
        console.log(line1[lineCount].type,line1[lineCount].name);
       } 

     if (lineCount==0){
          circle1[lineCount]=makeCircle( posX2, posY2, null,null);
          canvas.add(circle1[lineCount]); 
      }
      if (lineCount>0){
         circle1[lineCount]= makeCircle(line1[lineCount].get('x2'), line1[lineCount].get('y2'), line1[lineCount],null);
         canvas.add(circle1[lineCount]); 
         circle1[lineCount-1].line2 =line1[lineCount];
      } 
      
     lineCount=lineCount+1;    
}

canvas.on('mouse:down', function(e) {
    var obj2 = e.target;
    if (obj2!= null){console.log(obj2.type);}
   
  if (obj2==null){
         posX1 = posX2;
         posY1 = posY2;
         var pointer = canvas.getPointer(e.e);
         posX2 = pointer.x;
         posY2 = pointer.y;
         drawPoly();
		 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();
		 });
	     
      }else{lineCount=0;}
}); 



</script>
</body></html>

Open in new window

My code is working.

But when i save canvas to DB and then  close  the page, and then reopen it again I lose  dragging of lines behind circle.
I did add next to my code:
var jsonToPHP;
function  saveJsonF(){
var jsonToPHP= JSON.stringify(canvas.toObject(['id','name','line1','line2']));
canvas.clear();
}
function  getJsonF(){
    canvas.loadFromJSON(jsonToPHP, function() {    
    canvas.renderAll();
      });
}
document.getElementById("saveJsonID").onclick = saveJsonF;
document.getElementById("getJsonID").onclick = getJsonF;

Open in new window


 Can you test it pleas?
 With clicks on canvas you need to get  lines and circles. With clicking on same circle you are ending one polyline.
If you drag one circle attached lines need to follow it.


After clicking on saveJson button canvas has to be stored and cleared. And after clicking on getJson, you need to get back canvas elements
and they need to follow the pressed circle.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">


 <script src="http://fabricjs.com/lib/fabric.js"></script>

<script>
var canvas = new fabric.Canvas('c');
 
  
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';



var line1=[];

 function makeLine(coords) {
    return new fabric.Line(coords, {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 5,
    selectable: false,
     name:'polyline'
    });
 }
 var circle1=[];
  function makeCircle(left, top, line1, line2) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 2,
      radius: 6,
      fill: '#fff',
      stroke: '#666',
      name:'polyline'
    });
    c.hasControls = c.hasBorders = false;

    c.line1 = line1;
    c.line2 = line2;

    return c;
  }
 
 
var clickonobject ;
var objectIndex;
var lineCount=0;
var posX1=0;
var posY1=0;
var posX2=0;
var posY2=0;
function drawPoly(){
  
 
      
       if (lineCount!=0){
       line1[lineCount] = makeLine([posX1, posY1, posX2, posY2 ]);
       canvas.add(line1[lineCount]);
        console.log(line1[lineCount].type,line1[lineCount].name);
       } 

     if (lineCount==0){
          circle1[lineCount]=makeCircle( posX2, posY2, null,null);
          canvas.add(circle1[lineCount]); 
      }
      if (lineCount>0){
         circle1[lineCount]= makeCircle(line1[lineCount].get('x2'), line1[lineCount].get('y2'), line1[lineCount],null);
         canvas.add(circle1[lineCount]); 
         circle1[lineCount-1].line2 =line1[lineCount];
      } 
      
     lineCount=lineCount+1;    
}

canvas.on('mouse:down', function(e) {
    var obj2 = e.target;
    if (obj2!= null){console.log(obj2.type);}
   
  if (obj2==null){
         posX1 = posX2;
         posY1 = posY2;
         var pointer = canvas.getPointer(e.e);
         posX2 = pointer.x;
         posY2 = pointer.y;
         drawPoly();
      }else{lineCount=0;}
} 

 var leftx2,topy2;
var moveHandler = function (evt) {
    var obj = evt.target;
  leftx2 = obj.get('left');
  topy2 = obj.get('top');
   //console.log(leftx2);
  //console.log(topy2);
    obj.line1 && obj.line1.set({ 'x2': obj.left, 'y2': obj.top });
    obj.line2 && obj.line2.set({ 'x1': obj.left, 'y1': obj.top });
}


var jsonToPHP;
function  saveJsonF(){
var jsonToPHP= JSON.stringify(canvas.toObject(['id','name','line1','line2']));
canvas.clear();

}
function  getJsonF(){
    canvas.loadFromJSON(jsonToPHP, function() {    
    canvas.renderAll();
      });
}
document.getElementById("saveJsonID").onclick = saveJsonF;
document.getElementById("getJsonID").onclick = getJsonF;

</script>
</head>
<body>
       <canvas  id="c5" width="1060" height="550"  > 
        <input type="button"  id="saveJsonID" value=" saveJson"/> 
        <input type="button"   id="getJsonID" value=" getJson"/>

 
</div>
</body></html>

Open in new window

var jsonToPHP= JSON.stringify(canvas.toObject(['id','name','line1','line2']));

Take "var" from previous code line 106 pleas.

I have next error after retrieving objects on canvas back (press on getJason button) and when moving of circle (check attached picture).

Uncaught TypeError: obj.line1.set is not a function
    at i.moveHandler (createObject1.js?ver=1.0.0:538)
Untitled1a.png
obj.line1.set is not defined after reloading of Json.

Check the attached picture:
green ellipse is on moving of circle before storing canvas to Json.
red ellipse after recalling of Json and moving of circle.
Untitled3a.png
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Can you run my code?
Dear Julian Hansen

It is pretty clear what the error is saying - there is no function set() defined on that object. Are you sure you are using it correctly?

What must i do to not have situation illustrated in red ellipse in my last attached   picture?

(maybe the problem is that  when Json is doing stringify of objects, it does not also includes set() function)
I was trying with next but still can not  store functions.
Can you see why?

function  saveJsonF(){
  jsonF=JSON.stringify(canvas,function(key, value){
            return (typeof value === 'function' ) ? value.toString() : value;
        });
        console.log("object functions"+jsonF);
canvas.clear();
}

Open in new window