Cloning objects in Fabric.js

2020-06-03 02:30发布

问题:

I am cloning a selected object on a canvas in Fabric.js using a simple function.

function duplicateObj() {
  var obj = canvas.getActiveObject();
  var clone = fabric.util.object.clone(obj);
  clone.set({left: 100,top: 100});
  canvas.add(clone); 
}

That works absolutely fine. Now if I work with the object and the clone is not required anymore and I select and delete it, both objects, the clone and the original object are deleted. The delete function is:

function deleteObj() {
  var obj = canvas.getActiveObject();
  canvas.fxRemove(obj);
}

The objects are the same. Is there are way to clone objects and make the clone independent of the of the original? I tried this:

function duplicateObj() {
  var obj = canvas.getActiveObject();
  var clone = fabric.util.object.clone(obj);
  clone.initialize();
  $.extend(clone, obj);
  fabric.util.object.extend(clone, obj);
  clone.set({left: 100,top: 100});
  canvas.add(clone); 
}

It works, however the objects are the same again and if I only use initialize I am ending up with an object that has now properties set.

回答1:

here is the solution

 var object = fabric.util.object.clone(canvas.getActiveObject());
    object.set("top", object.top+5);
    object.set("left", object.left+5);
     canvas.add(object);


回答2:

for fabricjs 2.0

    $(".copy").on("click", function () {
                    var activeObject = canvas.getActiveObject();
                    activeObject.clone(function (cloned) {
                        canvas.discardActiveObject();
                        cloned.set({
                            top: cloned.top + 20,
                            evented: true
                        });
                        if (cloned.type === 'activeSelection') {
                            // active selection needs a reference to the canvas.
                            cloned.canvas = canvas;
                            cloned.forEachObject(function (obj) {
                                canvas.add(obj);
                            });
                            cloned.setCoords();
                        } else {
                            canvas.add(cloned);
                        }
                        canvas.setActiveObject(cloned);
                        canvas.requestRenderAll();
                    });
    });


回答3:

I was having a similar issue where actions on the clone would affect the original object. I opted to just serialize the object and deserialize it into a new object:

var copyData = canvas.getActiveObject().toObject();
fabric.util.enlivenObjects([copyData], function(objects) {
  objects.forEach(function(o) {
    o.set('top', o.top + 15);
    o.set('left', o.left + 15);
    canvas.add(o);
  });
  canvas.renderAll();
});


回答4:

This worked very well for me, and the cloned object is totally unlinked from the original:

var object = canvas.getActiveObject();

object.clone(function(clone) {
    canvas.add(clone.set({
        left: object.left + 10, 
        top: object.top + 10
    }));
});

And you can do it to clone all selected objects:

var activeObjects = canvas.getActiveObjects();

if (activeObjects) {
    activeObjects.forEach(function(object) {

        object.clone(function(clone) {
            canvas.add(clone.set({
                left: object.left + 10, 
                top: object.top + 10
            }));
        })

    });
}

I hope it can help you!



回答5:

You can use

var obj = canvas.getActiveObject();
obj.clone(function(c) {
   canvas.add(c.set({ left: 100, top: 100, angle: -15 }));
});

Here you can see it working: http://fabricjs.com/opacity_mouse_move/



回答6:

Here is my implementation of cloning selected object or group.

https://jsfiddle.net/milanhlinak/rxtjm7w0/1/

<!DOCTYPE html>
<html>

<head>
    <script type="text/javascript" src="lib/jquery-3.1.1.min.js"></script>
    <script type="text/javascript" src="lib/fabric.min.js"></script>
</head>

<body>

    <button onclick="cloneSelected()">Clone selected</button>
    <canvas id="canvas" style="border: 1px solid #cccccc"></canvas>

    <script>
        var canvas = new fabric.Canvas('canvas', {
            width: 500,
            height: 500,
        });

        canvas.add(new fabric.Rect({
            left: 100,
            top: 100,
            width: 50,
            height: 50,
            fill: '#faa'

        }));
        canvas.add(new fabric.Circle({
            left: 300,
            top: 300,
            radius: 25,
            fill: '#afa'
        }));


        function cloneSelected() {
            console.log('cloneSelected');

            var activeObject = canvas.getActiveObject();
            var activeGroup = canvas.getActiveGroup();

            if (activeObject) {
                console.log('object selected');

                var clonedObject = null;
                var json = activeObject.toJSON();
                if (json.type == 'rect') {
                    clonedObject = new fabric.Rect(json);
                } else if (json.type == 'circle') {
                    clonedObject = new fabric.Circle(json);
                } else {
                    console.log('unknown object type: ' + json.type);
                    return;
                }

                var oldLeft = clonedObject.getLeft();
                var oldTop = clonedObject.getTop();

                clonedObject.setLeft(oldLeft + 10);
                clonedObject.setTop(oldTop + 10);

                var boundingRect = clonedObject.getBoundingRect(true);
                if (boundingRect.left + boundingRect.width > canvas.getWidth()) {
                    clonedObject.setLeft(oldLeft);
                }
                if (boundingRect.top + boundingRect.height > canvas.getHeight()) {
                    clonedObject.setTop(oldTop);
                }

                canvas.add(clonedObject);
                canvas.setActiveObject(clonedObject);
                canvas.renderAll();
                console.log('selected object cloned');

            } else if (activeGroup) {
                console.log('group selected');

                canvas.discardActiveGroup();

                var clonedObjects = [];

                activeGroup.getObjects().forEach(function (object) {

                    var clonedObject = null;

                    var json = object.toJSON();
                    if (json.type == 'rect') {
                        clonedObject = new fabric.Rect(json);
                    } else if (json.type === 'circle') {
                        clonedObject = new fabric.Circle(json);
                    } else {
                        console.log('unknown object type: ' + json.type);
                        return;
                    }

                    clonedObject.setCoords();
                    canvas.add(clonedObject);
                    clonedObject.set('active', true);
                    clonedObjects.push(clonedObject);
                });

                var group = new fabric.Group(clonedObjects.reverse(), {
                    canvas: canvas
                });

                group.addWithUpdate(null);

                var oldLeft = group.getLeft();
                var oldTop = group.getTop();

                group.setLeft(oldLeft + 10);
                group.setTop(oldTop + 10);

                var boundingRect = group.getBoundingRect(true);
                if (boundingRect.left + boundingRect.width > canvas.getWidth()) {
                    group.setLeft(oldLeft);
                }
                if (boundingRect.top + boundingRect.height > canvas.getHeight()) {
                    group.setTop(oldTop);
                }

                group.setCoords();
                canvas.setActiveGroup(group);
                group.saveCoords();
                canvas.renderAll();
                console.log('selected objects cloned');
            } else {
                console.log('no object selected');
            }

        }
    </script>

</body>

</html>


回答7:

Check the demo for Copy and Paste here: http://fabricjs.com/copypaste

Here is the code to copy/paste or clone the selected object.

function Clone() {
    Copy();
    Paste()
}

function Copy() {
    // clone what are you copying since you
    // may want copy and paste on different moment.
    // and you do not want the changes happened
    // later to reflect on the copy.
    canvas.getActiveObject().clone(function(cloned) {
        _clipboard = cloned;
    });
}

function Paste() {
    // clone again, so you can do multiple copies.
    _clipboard.clone(function(clonedObj) {
        canvas.discardActiveObject();
        clonedObj.set({
            left: clonedObj.left + 10,
            top: clonedObj.top + 10,
            evented: true,
        });
        if (clonedObj.type === 'activeSelection') {
            // active selection needs a reference to the canvas.
            clonedObj.canvas = canvas;
            clonedObj.forEachObject(function(obj) {
                canvas.add(obj);
            });
            // this should solve the unselectability
            clonedObj.setCoords();
        } else {
            canvas.add(clonedObj);
        }
        _clipboard.top += 10;
        _clipboard.left += 10;
        canvas.setActiveObject(clonedObj);
        canvas.requestRenderAll();
    });
}