如何在Fabric.js中恢复多选缩放对象的原始尺寸?
Fabric.js 撤销功能缩放恢复异常问题
我正在基于Fabric.js实现撤销功能,当前代码在撤销位置修改时正常,但对象缩放后,仅能调整选框大小,无法恢复内部对象的尺寸。
现有撤销核心代码:
let groupObjects = lastAction.before._objects; if (groupObjects) { let selectionGroup = new fabric.ActiveSelection(groupObjects, { canvas: canvas }); selectionGroup.set({ ...lastAction.before }); selectionGroup.setCoords(); canvas.setActiveObject(selectionGroup); } canvas.renderAll();
lastAction.before的赋值逻辑:
lastAction = { before: fabric.util.object.clone(canvas.getActiveObjects()) }
我尝试遍历单个对象恢复属性,但问题依旧:
groupObjects.forEach((obj, index) => { let objectToRevert = canvas.getObjects().find(o => o.objectId === obj.objectId); objectToRevert.set({ left: obj.left, top: obj.top, scaleX: obj.scaleX, scaleY: obj.scaleY, angle: obj.angle, width: obj.width, height: obj.height, flipX: obj.flipX, flipY: obj.flipY, skewX: obj.skewX, skewY: obj.skewY }); objectToRevert.setCoords(); });

问题根源
canvas.getActiveObjects()返回的是当前选中对象的引用集合,直接用fabric.util.object.clone克隆时,无法完整复制ActiveSelection内部对象的变换状态,属于浅拷贝层面的问题。- 直接给ActiveSelection设置属性,只会修改选框的外观参数,不会同步更新内部对象的实际变换值。
- 遍历恢复时,可能因
objectId匹配偏差、未触发对象重绘逻辑,导致属性设置未生效。
修复方案
1. 正确保存对象的完整状态
记录操作时,需要深度克隆每个选中对象的可序列化完整状态,而非直接克隆getActiveObjects()的结果:
// 修改操作记录的赋值逻辑 const activeObjects = canvas.getActiveObjects(); const clonedObjects = activeObjects.map(obj => { // 导出并克隆对象的核心状态属性 return fabric.util.object.clone(obj.toObject([ 'objectId', 'left', 'top', 'scaleX', 'scaleY', 'angle', 'width', 'height', 'flipX', 'flipY', 'skewX', 'skewY' ])); }); lastAction = { before: clonedObjects };
2. 撤销时逐个恢复对象状态
撤销时先逐个恢复对象的原始状态,再重新创建选中组保证选框与对象状态匹配:
// 修改撤销逻辑 lastAction.before.forEach(clonedObj => { const targetObj = canvas.getObjects().find(o => o.objectId === clonedObj.objectId); if (targetObj) { // 用克隆的完整状态覆盖当前对象 targetObj.set(clonedObj); targetObj.setCoords(); } }); // 重新创建选中组,确保选框与对象状态同步 const targetObjects = lastAction.before .map(obj => canvas.getObjects().find(o => o.objectId === obj.objectId)) .filter(Boolean); const selectionGroup = new fabric.ActiveSelection(targetObjects, { canvas: canvas }); canvas.setActiveObject(selectionGroup); canvas.renderAll();
3. 关键注意点
- 确保每个画布对象都有唯一的
objectId,避免对象匹配错误。 - 使用
toObject()导出可序列化状态再克隆,比直接克隆对象实例更可靠,能完整保留变换参数。 - 恢复对象后必须调用
setCoords()更新碰撞检测区域,最后调用renderAll()触发画布重绘。
内容的提问来源于stack exchange,提问作者threeFatCat
相关产品推荐
相关产品推荐

