0

你能帮我弄清楚这里发生了什么吗?

基本上我想将 FabricJS 与 ReactJS 和 Redux 一起使用。我想将当前选择的对象存储在 redux 存储中。但是在保存多选的活动对象时,它似乎有一种奇怪的行为。

let selectedObjects = null;
let canvas = new fabric.Canvas('canvas-area', {
  preserveObjectStacking: true,
  width: 500,
  height: 500
});

canvas.add(new fabric.Rect({
  left: 100,
  top: 100,
  fill: 'blue',
  width: 100,
  height: 100
}));

canvas.add(new fabric.Circle({
  radius: 50,
  fill: 'green',
  left: 200,
  top: 200
}));

canvas.renderAll();

// =======================

document.querySelector('#save-selection').addEventListener('click', ()=> {
  //selectedObjects = Object.assign({}, canvas.getActiveObject());
  selectedObjects = canvas.getActiveObject();
  canvas.discardActiveObject();
  canvas.renderAll();
});

document.querySelector('#apply-saved-selection').addEventListener('click', ()=> {
	canvas.setActiveObject(selectedObjects);
  canvas.renderAll();
});
<html>
  <body>
    <button id='save-selection'>Save Selection</button>
    <button id='apply-saved-selection'>Apply Saved Selection</button>
    <canvas id='canvas-area'></canvas>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.3/fabric.min.js"></script>
  </body>
</html>

基本上你使用上面的代码片段的方式是:

用例 1:单个选定对象

  1. 选择单个对象。
  2. 单击保存选择(它将保存当前选定的对象并清除当前画布选择)。
  3. 单击应用保存的选择
  4. 拖动当前选定的对象,选择和选定的对象保持同步,应用程序按预期工作。

用例 2:多选

  1. 选择多个对象。
  2. 单击保存选择
  3. 单击应用保存的选择
  4. 拖动当前选中的对象,可以看到,只有选中的对象被拖动,实际选中的对象被留下(不同步)。

您能帮我弄清楚如何正确保存所选对象以供以后使用吗?

提前致谢

注意:我使用的是最新的 FabricJS (2.3.3)

4

1 回答 1

1

更新:

将选定的元素存储在 redux 存储中是不明智的。当我们处理分组选择、分组对象、剪切图像等时,重新加载保存的选定元素非常困难......

底线,不要将选定的元素保存在 redux 存储中。

===================

更新:

我在下面的回答有一个缺陷,那就是在加载保存的旋转选择时不会保留选择的旋转角度。

仍在寻找比我目前拥有的更好的答案。

===================

好的,看来我们需要有不同的方法来重新加载多选对象。

概括

我们需要使用画布中与保存的选区中的对象相对应的确切对象来创建新选区。

// Extend fabric js so that all objects inside the canvas
// will have the custom id attribute
// We will use this later to determine which is which
fabric.Object.prototype.id = undefined;

let selectedObjects = null;
let canvas = new fabric.Canvas('canvas-area', {
  preserveObjectStacking: true,
  width: 500,
  height: 500
});

canvas.add(new fabric.Rect({
  id: 'unique-id-01',
  left: 100,
  top: 100,
  fill: 'blue',
  width: 100,
  height: 100
}));
canvas.add(new fabric.Circle({
  id: 'unique-id-02',
  radius: 50,
  fill: 'green',
  left: 200,
  top: 200
}));
canvas.add(new fabric.Rect({
  id: 'unique-id-03',
  left: 300,
  top: 300,
  fill: 'red',
  width: 100,
  height: 100
}));
canvas.renderAll();


// =======================

document.querySelector('#save-selection').addEventListener('click', ()=> {
  //selectedObjects = Object.assign({}, canvas.getActiveObject());
  selectedObjects = canvas.getActiveObject();
  canvas.discardActiveObject();
  canvas.renderAll();
});

document.querySelector('#apply-saved-selection').addEventListener('click', ()=> {

  if (selectedObjects.type === 'activeSelection') {
  	
    let canvasObjects = canvas.getObjects(); // Get all the objects in the canvas
    let selObjs = [];
    
    // Loop through all the selected objects
    // Then loop through all the objects in the canvas
    // Then check the id of each objects if they matched
    // Then store the matching objects to the array
    for (let so of selectedObjects._objects) {
    	for (let obj of canvasObjects) {
      	if (obj.id === so.id) {
        	selObjs.push(obj); // Store the canvasObjects item, not the selectedObjects item.
          break;
        }
      }
    }
    
    // Create a new selection instance using the filtered objects above
    let selection = new fabric.ActiveSelection(selObjs, {
    	canvas: canvas
    });
    
    canvas.setActiveObject(selection); // Profit
    
  } else { // Single object selected, load directly
  	canvas.setActiveObject(selectedObjects);
  }
  
  canvas.renderAll();
});
<html>
  <body>
    <button id='save-selection'>Save Selection</button>
    <button id='apply-saved-selection'>Apply Saved Selection</button>
    <canvas id='canvas-area'></canvas>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.3/fabric.min.js"></script>
  </body>
</html>

  1. 我们需要扩展fabric js并添加自定义id属性。稍后我们将使用它来比较 fabric js 实例中的对象和保存的选择中的对象。

  2. 循环遍历fabric js实例对象和保存的选择对象,并使用我们之前添加的自定义id确定fabric js实例中的哪些对象被选中。

  3. 使用步骤 2 中过滤的对象创建新的选择实例new fabric.ActiveSelection 。

  4. fabric.ActiveSelection实例设置为fabric js 实例的activeObject

  5. 利润

Fabric JS 选择处理参考

于 2018-08-02T05:23:53.840 回答