Fabric.js复制选定组的粘贴

时间:2015-06-19 02:25:15

标签: javascript canvas fabricjs

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

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

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

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

我尝试过克隆并添加克隆组,如下所示:

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

现在运行此代码后,克隆的组对象似乎可以添加,定位和选择,但只要我单击画布清除选择,克隆的组对象就会跳转到画布上的其他位置。此外,克隆的对象不能单独选择,并且选择位置与新对象位置不同步。无论如何我确定我错过了什么,但我不确定是什么。任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:1)

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

我通过克隆群组给你jsFiddle

答案 1 :(得分:1)

有同样的问题,你的回答对我有很多帮助。

这是一个显示如何做的小提琴。

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();
}

答案 2 :(得分:0)

感谢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);
};

此代码更新选择。请注意,要选择组中的组和单个对象,我需要为每个对象调用 object.set('active'),true) $ scope.isGroup(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();
}