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();
}
假设我在 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();
}