Fabric.js 复制粘贴所选组

Fabric.js copy paste of selected group

假设我在 fabric.js canvas 上选择了多个对象,并且可以使用 getActiveGroup 获取这组对象。任何人都可以提供如何将组复制并粘贴到新组中的示例,其中:

(a) 复制组中的每个对象保留其相对于其他复制对象的相对位置

(b) 复制的组作为一个整体位于某个指定的 x,y 位置

(c) 复制的组对象在粘贴后被选择为一个组,但如果清除选择,它们将被视为 canvas

上的单个对象

我试过像这样通过克隆和添加克隆组来粘贴:

canvas.getActiveGroup().clone(function(clone) {
    clone.left = 100;
    clone.top = 100;
    canvas.add(clone);
    canvas.deactivateAll();
    canvas.setActiveGroup(clone).renderAll();
});

现在,在这段代码 运行 之后,克隆的组对象似乎已添加、定位和选择正常,但是一旦我单击 canvas 清除选择,克隆的组对象就会跳转到 canvas 上的不同位置。此外,克隆对象不可单独选择,并且选择位置与新对象位置不同步。无论如何,我确定我遗漏了一些东西,但我不确定是什么。感谢任何帮助。

您应该尝试 canvas.getActiveGroup().forEachObject(function(o) 组类型对象,然后克隆它们。

我克隆了一个群组给你jsFiddle

感谢 Nistor 帮助我入门。我必须做一些额外的工作才能得到我想要的结果。这是我的粘贴功能(请注意,我使用的是 Angular,但其他人可以根据需要进行调整)。在调用此函数之前,必须将对象复制到剪贴板数组。

// Handle a paste request
$scope.paste = function() {

    // Make sure we have something in the clipboard
    if ($scope.shared.clipboard.length == 0) {
        return;
    }

    // Check if we have single or multiple objects on the clipboard
    if ($scope.shared.clipboard.length == 1) {
        $scope.shared.clipboard[0].clone(function(clone) {
            pasteOne(clone);
            $scope.select(clone);
        });
    } else {
        var group = new fabric.Group();
        for (var index = ($scope.shared.clipboard.length - 1); index >= 0; index--) {
            $scope.shared.clipboard[index].clone(function(clone) {
                pasteOne(clone);
                group.addWithUpdate(clone);
                // Clone is async so wait until all group objects are cloned before selecting
                if (group.size() == $scope.shared.clipboard.length) {
                    group.setCoords();
                    $scope.select(group);
                }
            });
        }
    }
};

此函数保留每个粘贴对象的相对偏移量。粘贴位置可以设置为任意值:

// Paste a single clone onto the canvas
var pasteOne = function(clone) {
    clone.left += $scope.shared.pastePosition.x;
    clone.top += $scope.shared.pastePosition.y;
    clone.setCoords();
    $scope.canvas.add(clone);
};

此代码更新 selection。请注意,对于 select 组和组中的单个对象,我需要为每个对象调用 object.set('active'), true)$scope.isGroup(select) 只是检查 select 类型是否为 'group'.

// Update the selection
$scope.select = function(select) {

    // Clear the selection
    $scope.canvas.deactivateAll();
    $scope.canvas.discardActiveGroup();

    // Handle group vs single object selections
    if ($scope.isGroup(select)) {
        $scope.canvas.setActiveGroup(select);
        select.forEachObject(function(object) {
            object.set('active', true);
        });
    } else {
        $scope.canvas.setActiveObject(select);
    }

    // Refresh the canvas
    $scope.canvas.renderAll();
}

遇到了同样的问题,你的回答对我帮助很大。

这里 fiddle 展示了如何操作。

https://jsfiddle.net/Lcdrohk4/1/

canvasWrapper.addEventListener('keydown', function(e) {
//Copy paste function for canvas objects

//If ctrl is pressed, set ctrlDown to true
if (e.keyCode == 17) ctrlDown = true;

//Handle ctrl+c
if (ctrlDown && e.keyCode == 67) {
    //reset array with copied objects
copiedObjects = [];

//Get the activeObject and the ActiveGroup
var activeObject = canvas.getActiveObject(),
  activeGroup = canvas.getActiveGroup();

//If multiple items are selected the activeGroups will be true
if (activeGroup) {
    //get the objects from the activegroup
  var objectsInGroup = activeGroup.getObjects();
  //Discard the activeGroup
  canvas.discardActiveGroup();

  //Push all items from the activeGroup into our array
  objectsInGroup.forEach(function(object) {
    copiedObjects.push(object);
  });
} else if (activeObject) { //If one item is selected then acriveObject will be true
  copiedObjects.push(activeObject); //push our selected item into the array
}
};

//handle ctrl+v
if (ctrlDown && e.keyCode == 86) {
var count = 0;
//Check if we have only one item we want to copy
if (copiedObjects.length == 1) {
    //check if we can handle async cloning
  if (fabric.util.getKlass(copiedObjects[0].type).async) {
        copiedObjects[0].clone(function(clone) {

      //Add our item
      pasteOne(clone);

      //Select our item
      selectAll(1);
    });
  } else { //Sync cloning

    //Add our item
    pasteOne(copiedObjects[0].clone());

    //Select our item
    selectAll(1);
  }
  //Handle multiple item copying
 } else if(copiedObjects.length > 1) { 
  for (var index = (copiedObjects.length - 1); index >= 0; index--) {
    //check if we can handle async cloning
    if (fabric.util.getKlass(copiedObjects[index].type).async) {
            copiedObjects[index].clone(function(clone) {

        //Add our item
        pasteOne(clone);
        count++;
        //if we have added all our items we can now select them
        if (count == copiedObjects.length) {
          selectAll(copiedObjects.length);
        }
      });
    }else{ //sync cloning

        //Add our item
        pasteOne(copiedObjects[index].clone());

      count++;
      //if we have added all our items we can now select them
      if (count == copiedObjects.length) {
        selectAll(copiedObjects.length);
      }
    }
  }
 }
}

//Delete selected items with the delete button
if(e.keyCode == 46){
 var activeObject = canvas.getActiveObject(),
 activeGroup = canvas.getActiveGroup();
 if (activeGroup) {
   var objectsInGroup = activeGroup.getObjects();
   canvas.discardActiveGroup();
   objectsInGroup.forEach(function(object) {
       canvas.remove(object);
   });
 }
 else if (activeObject) {
  canvas.remove(activeObject);
  }
}
}, false);

//Set ctrlDown to false when we release the ctrl key
canvasWrapper.addEventListener('keyup', function(e) {
  if (e.keyCode == 17) ctrlDown = false;
});

//Add our item to the canvas
function pasteOne(clone) {
 clone.left += 100; //add 100 to the left position
 clone.top += 100; //add 100 to the top position
 clone.set('canvas', canvas); //Set the canvas attribute to our canvas
 clone.setCoords(); //Must call this when we cahnged our coordinates
 canvas.add(clone); //Add the item
};

//Select all copied items. numberOfItems is the count of how many items where copied
function selectAll(numberOfItems) {

// Clear the selection
canvas.deactivateAll();
canvas.discardActiveGroup();

//new array for handling the newly pasted objects
var objs = new Array();

//get all objects in the canvas
var canvasObjects = canvas.getObjects();

//counter for keeping track how many items we have in "objs"
var count = 0;

//loop from the end of all items in the canvas
for (var index = (canvasObjects.length - 1); index >= 0; index--) {

  //Push the item into objs and set the active state to true
  if (count < numberOfItems) objs.push(canvasObjects[index].set('active', true));

  count++;
}
//Create new fabric group with the copied objects
var group = new fabric.Group(objs, {
  originX: 'center',
  originY: 'center'
});

//set the group as the new active group
canvas.setActiveGroup(group.setCoords()).renderAll();
}