Search code examples
fabricjs

FabricJs- Cloning objects loses custom properties


I have set custom properties on SVG objects and on paths within the SVG objects.

Each object I add to the canvas also gets assigned an 'id' property, as well as some others properties that I use to interact with the objects in the app.

So far, when I clone these objects, I have been able to retain the properties that are on the SVG object by storing them in a session variable prior to cloning, then adding them back after cloning.

My problem is with the properties that are set on each of the object.paths. I have an 'id' property for each path, which I use for some functions that can manipulate the paths within the object.

So for example, before I group the object, the object.paths attribute looks like this...

paths: Array(4)
0: klass {id: "_25mm_x_400mm_ROUND", d: "M400.5,60.5A21.52,21.52", fill: "#ccc", dirty: false, stroke: "#000", …}
1: klass {id: "_25mm_x_400mm_ROUND", d: "M400.5,60.5v25c0", stroke: "#000", dirty: false, strokeMiterLimit: 10, …}
2: {id: "shapeTopColor", d: "M400.5,60.5A21.52,21.52", fill: "rgba(0, 0, 0, 0)", dirty: false, stroke: "#000", …}
3: {id: "shapeSideColor", d: "M400.5,60.5v25c0", stroke: "#000", dirty: false, strokeMiterLimit: 10, …}

Then, after ungrouping the object, the object.paths attribute looks like this...

paths: Array(4)
0: klass {type: "path", originX: "left", originY: "top", left: 0.4999999999999982, top: 0.5, …}
1: klass {type: "path", originX: "left", originY: "top", left: 0.5, top: 60.5, …}
2: klass {type: "path", originX: "left", originY: "top", left: 0.4999999999999982, top: 0.5, …}
3: klass {type: "path", originX: "left", originY: "top", left: 0.5, top: 60.5, …}

This breaks some functions that use the 'shapeTopColor and 'shapeSideColor' ids to change fill attributes for each path. So if a user groups an object, then ungroups it, they are no longer able to change the colour of the object.

Here is the code I am using to group objects...

    export function groupSelectedItems() {
    
      canvas = document.getElementById("c").fabric;
    
      var activegroup = canvas.getActiveGroup();
      var objectsInGroup = activegroup.getObjects();
    
      var objectIds = [];
    
      activegroup.clone(function(newgroup) {
    
          canvas.discardActiveGroup();
          objectsInGroup.forEach(function(object) {
              objectIds.push({
                'id':object.id,
                'componentType':object.componentType,
                'shape': object.shape,
                // paths = object.paths //Tried this but causes errors.
               });
              canvas.remove(object);
          });
    
          newgroup.setControlsVisibility({'tl': false, 'tr': false, 'bl': false, 'br': false, 'ml': false, 'mr': false, 'mb': false, 'mt': false});
          canvas.add(newgroup);
    
          //Store the objects id's on to a session variable.
          Session.set('objectIds', objectIds);
    
          //put original objects id's back onto the new groups objects respectively.
          var objectsInNewGroup = newgroup.getObjects();
          objectsInNewGroup.forEach(function(object, key) {
              Session.get('objectIds').forEach(function(o, i) {
                if (key == i) {
                  object.id = o.id
                  object.componentType = o.componentType,
                  object.shape = o.shape
                  // object.paths = o.paths
                }
              });
          });
    
      });
    }

So my question is, how can I clone an object or group and not lose any custom attributes I have set?


Solution

  • DEMO

    var canvas = new fabric.Canvas('c');
    var rect1 = new fabric.Rect({
      id: 1,
      width: 100,
      height: 100,
      fill: 'red',
      componentType: 'a1',
      shape: 'round1'
    });
    var rect2 = new fabric.Rect({
      id: 2,
      left:10,
      top:20,
      width: 100,
      height: 100,
      fill: 'magenta',
      componentType: 'a2',
      shape: 'round2'
    });
    var rect3 = new fabric.Rect({
      id: 3,
      left:30,
      top:30,
      width: 100,
      height: 100,
      fill: 'yellow',
      componentType: 'a3',
      shape: 'round3'
    });
    var group = new fabric.Group([rect1, rect2, rect3]);
    canvas.add(group)
    canvas.setActiveObject(group);
    
    function cloneObj() {
      group.clone(function(newgroup) {
        canvas.add(newgroup.set({
         left: newgroup.left + 10,
         top: newgroup.top + 10
        }));
        console.log(newgroup);
      }, ['id', 'componentType', 'shape']);
    }
    canvas {
        border: 1px solid #999;
    }
    <script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
    <button onclick='cloneObj()'>Clone</button>
    <canvas id="c" width="700" height="400"></canvas>

    clone accepts a callback and array for additional property to include in cloned object.