FabricJS 选择处理多个对象
FabricJS selection handling multiple objects
我正在努力处理多个对象的选择。所需的行为是将每个被单击的对象添加到当前选择中。类似于按住 shift 键,但也应将使用拖动选项的选择添加到现有选择中。 fabricjs 的当前行为是在按下 shift 键时创建一个新的选择。此外,单击 canvas 上的空白 space 时不应清除选择。只有在单击作为选择的一部分的单个对象时才能取消选择对象(当拖动所选对象时应保持选中状态)。或者通过单击其他按钮清除全部选择(需要额外的用户确认)。
我尝试了使用“selection:created”和“selection:updated”的不同设置,但这要么弄乱了选择,要么导致无限循环,因为在更新中修改选择也会再次触发更新。
canvas.on("selection:updated", (event) => {
event.selected.forEach((fabImg) => {
if (!this.selectedImages.includes(fabImg)) {
this.selectedImages.push(fabImg);
}
});
var groupSelection = new fabric.ActiveSelection(this.selectedImages);
canvas.setActiveObject(groupSelection);
});
点击空白时防止清除 canvas 已通过以下方式解决:
var selection = [];
canvas.on("before:selection:cleared", (selected) => {
selection = this.canvas.getActiveObjects();
});
canvas.on("selection:cleared", (event) => {
var groupSelection = new fabric.ActiveSelection(selection);
canvas.setActiveObject(groupSelection);
});
以防万一其他人感兴趣,我最终更改了 fabricjs 代码中的 3 个函数以实现所需的行为:
canvas.class.js:
_shouldClearSelection: function (e, target) {
var activeObjects = this.getActiveObjects(),
activeObject = this._activeObject;
return (
(target &&
activeObject &&
activeObjects.length > 1 &&
activeObjects.indexOf(target) === -1 &&
activeObject !== target &&
!this._isSelectionKeyPressed(e)) ||
(target && !target.evented) ||
(target &&
!target.selectable &&
activeObject &&
activeObject !== target)
);
}
刚刚删除了是否单击对象的检查,以在单击空白时停止删除selecting space。
_isSelectionKeyPressed: function (e) {
var selectionKeyPressed = false;
if (this.selectionKey == "always") {
return true;
}
if (
Object.prototype.toString.call(this.selectionKey) === "[object Array]"
) {
selectionKeyPressed = !!this.selectionKey.find(function (key) {
return e[key] === true;
});
} else {
selectionKeyPressed = e[this.selectionKey];
}
return selectionKeyPressed;
}
只需添加一个名为“always”的“虚拟”键来假装始终按住 shift 键。在 canvas 定义中只需添加此键:
this.canvas = new fabric.Canvas("c", {
hoverCursor: "hand",
selection: true,
backgroundColor: "#F0F8FF",
selectionBorderColor: "blue",
defaultCursor: "hand",
selectionKey: "always",
});
在 canvas_grouping.mixin.js 中:
_groupSelectedObjects: function (e) {
var group = this._collectObjects(e),
aGroup;
var previousSelection = this._activeObject;
if (previousSelection) {
if (previousSelection.type === "activeSelection") {
var currentActiveObjects = previousSelection._objects.slice(0);
group.forEach((obj) => {
if (!previousSelection.contains(obj)) {
previousSelection.addWithUpdate(obj);
}
});
this._fireSelectionEvents(currentActiveObjects, e);
} else {
aGroup = new fabric.ActiveSelection(group.reverse(), {
canvas: this,
});
this.setActiveObject(aGroup, e);
var objects = this._activeObject._objects.slice(0);
this._activeObject.addWithUpdate(previousSelection);
this._fireSelectionEvents(objects, e);
}
} else {
// do not create group for 1 element only
if (group.length === 1 && !previousSelection) {
this.setActiveObject(group[0], e);
} else if (group.length > 1) {
aGroup = new fabric.ActiveSelection(group.reverse(), {
canvas: this,
});
this.setActiveObject(aGroup, e);
}
}
}
这将扩展现有的拖动组-select,而不是覆盖现有的 selection。
我正在努力处理多个对象的选择。所需的行为是将每个被单击的对象添加到当前选择中。类似于按住 shift 键,但也应将使用拖动选项的选择添加到现有选择中。 fabricjs 的当前行为是在按下 shift 键时创建一个新的选择。此外,单击 canvas 上的空白 space 时不应清除选择。只有在单击作为选择的一部分的单个对象时才能取消选择对象(当拖动所选对象时应保持选中状态)。或者通过单击其他按钮清除全部选择(需要额外的用户确认)。
我尝试了使用“selection:created”和“selection:updated”的不同设置,但这要么弄乱了选择,要么导致无限循环,因为在更新中修改选择也会再次触发更新。
canvas.on("selection:updated", (event) => {
event.selected.forEach((fabImg) => {
if (!this.selectedImages.includes(fabImg)) {
this.selectedImages.push(fabImg);
}
});
var groupSelection = new fabric.ActiveSelection(this.selectedImages);
canvas.setActiveObject(groupSelection);
});
点击空白时防止清除 canvas 已通过以下方式解决:
var selection = [];
canvas.on("before:selection:cleared", (selected) => {
selection = this.canvas.getActiveObjects();
});
canvas.on("selection:cleared", (event) => {
var groupSelection = new fabric.ActiveSelection(selection);
canvas.setActiveObject(groupSelection);
});
以防万一其他人感兴趣,我最终更改了 fabricjs 代码中的 3 个函数以实现所需的行为:
canvas.class.js:
_shouldClearSelection: function (e, target) {
var activeObjects = this.getActiveObjects(),
activeObject = this._activeObject;
return (
(target &&
activeObject &&
activeObjects.length > 1 &&
activeObjects.indexOf(target) === -1 &&
activeObject !== target &&
!this._isSelectionKeyPressed(e)) ||
(target && !target.evented) ||
(target &&
!target.selectable &&
activeObject &&
activeObject !== target)
);
}
刚刚删除了是否单击对象的检查,以在单击空白时停止删除selecting space。
_isSelectionKeyPressed: function (e) {
var selectionKeyPressed = false;
if (this.selectionKey == "always") {
return true;
}
if (
Object.prototype.toString.call(this.selectionKey) === "[object Array]"
) {
selectionKeyPressed = !!this.selectionKey.find(function (key) {
return e[key] === true;
});
} else {
selectionKeyPressed = e[this.selectionKey];
}
return selectionKeyPressed;
}
只需添加一个名为“always”的“虚拟”键来假装始终按住 shift 键。在 canvas 定义中只需添加此键:
this.canvas = new fabric.Canvas("c", {
hoverCursor: "hand",
selection: true,
backgroundColor: "#F0F8FF",
selectionBorderColor: "blue",
defaultCursor: "hand",
selectionKey: "always",
});
在 canvas_grouping.mixin.js 中:
_groupSelectedObjects: function (e) {
var group = this._collectObjects(e),
aGroup;
var previousSelection = this._activeObject;
if (previousSelection) {
if (previousSelection.type === "activeSelection") {
var currentActiveObjects = previousSelection._objects.slice(0);
group.forEach((obj) => {
if (!previousSelection.contains(obj)) {
previousSelection.addWithUpdate(obj);
}
});
this._fireSelectionEvents(currentActiveObjects, e);
} else {
aGroup = new fabric.ActiveSelection(group.reverse(), {
canvas: this,
});
this.setActiveObject(aGroup, e);
var objects = this._activeObject._objects.slice(0);
this._activeObject.addWithUpdate(previousSelection);
this._fireSelectionEvents(objects, e);
}
} else {
// do not create group for 1 element only
if (group.length === 1 && !previousSelection) {
this.setActiveObject(group[0], e);
} else if (group.length > 1) {
aGroup = new fabric.ActiveSelection(group.reverse(), {
canvas: this,
});
this.setActiveObject(aGroup, e);
}
}
}
这将扩展现有的拖动组-select,而不是覆盖现有的 selection。