首页 fabric.js undo redo 丢失自定义属性问题

fabric.js undo redo 丢失自定义属性问题

2024-06-02 09:30:07 608 0

前端

本文收集了几种搜索网站的结果,进行了对比,并结合自身项目做了解决方案

如下是百度的回答:

在使用fabric.js进行开发时,如果在执行undo和redo操作时发现自定义属性丢失,很可能是因为你没有正确地序列化和反序列化这些自定义属性。

 

为了确保自定义属性在undo和redo操作中得以保留,你需要在初始化fabric.js对象时,使用toObject方法手动包含这些自定义属性。同时,在从对象的状态恢复时,使用fromObject方法来设置这些属性。

// 假设有一个自定义属性 customProp
var customProp = { value: 'custom' };

// 创建fabric对象时,包含自定义属性
var obj = new fabric.Circle({
  radius: 20,
  fill: 'red',
  customProp: customProp
});

// 将对象转换为对象状态(对象的JSON表示)
var objState = obj.toObject(['customProp']); // 包含自定义属性在内的序列化

// 之后,当你需要从这个状态恢复对象时
var restoredObj = new fabric.Circle(objState);

// 你可以这样设置自定义属性
restoredObj.set('customProp', customProp);

// 现在,当你执行 undo 和 redo 操作时,customProp 应该会被正确处理。

 

如下是腾讯爬取s't'a'c'k的回答:

text = new fabric.IText('Tap and Type');

// my new object
var newtext = text.toJSON();

// adding my attribute
newtext.attr1 = "value 1";

// object showing fine as json object
console.log(newtext);

// stringified object showing with my added attributes
console.log(JSON.stringify(newtext));

如下是博客园:

const a = canvas.toJSON(['id1', 'id2']);
const b = canvas.toDatalessJSON(['id1', 'id2']);
const c = canvas.toDatalessObject(['id1', 'id2']);
const d = canvas.toObject(['id1', 'id2']);

 

如下是github issue:

Undo redo is not something fabricJS ship with.
It has been discussed in various issues how to get there and different way to implement that, please have a search in past issues, closed or open

 

如下是stack:

fabric.StaticCanvas.prototype.getObjectByName  = function(name){
  if(!name || typeof name === 'undefined'){
  return [];
  }
  return this._objects.filter(function(o) {
      return o.name === name;
    });
}
var canvas = new fabric.Canvas('fabriccanvas');

canvas.counter = 0;
var newleft = 0;
canvas.selection = false;
var undoStack = [];
var redoStack = [];
addrect = function addrect(top, left, width, height, fill) {
    var rect = new fabric.Rect({
        top: document.getElementById("fabriccanvas").height,
        name: 'rectangle ' + canvas.counter,
        left: 0 + newleft,
        width: 100,
        height: 100,
        fill: '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6),
        //fix attributes applied for all rects
        opacity: 0.75,
        lockRotation: true,
        originX: 'left',
        originY: 'bottom',
        cornerSize: 15,
        hasRotatingPoint: false,
        perPixelTargetFind: true,
        minScaleLimit: 1
    })
    canvas.add(rect);
    undoStack.push({
     type:'added',
     object : rect
    })
    canvas.counter++;
    newleft += 100;
    redoStack=[];
}
var state = [];
var mods = 0;
var props = {};
canvas.on(
    'mouse:down', function (e) {
    var block = e.target;
    if(block){
    	 props.oldStage = {
       left:block.left,
       top:block.top,
       width:block.width,
       height:block.height,
       scaleX:block.scaleX,
       scaleY:block.scaleY,
       }
    }
}).on(
    'mouse:up', function (e) {
    var block = e.target;
    if(block){
    	 props.newStage = {
       left:block.left,
       top:block.top,
       width:block.width,
       height:block.height,
       scaleX:block.scaleX,
       scaleY:block.scaleY,
       }
       undoStack.push({
        objectName : block.name,
        type:'modified',
        oldStage:props.oldStage,
        newStage:props.newStage
       });
       props={};
    }
});



undo = function undo() {
    if(undoStack.length){
     var undoData = undoStack.pop();
     if(undoData && undoData.type){
       switch(undoData.type){
         case 'added':
         var objectByName = canvas.getObjectByName(undoData.object.name);
         if(objectByName.length){
           canvas.remove(objectByName[0]);

         }
         break;
         case 'modified':
         var objectByName = canvas.getObjectByName(undoData.objectName);
         if(objectByName.length){
          	for(var key in undoData.oldStage){
              objectByName[0].set(key, undoData.oldStage[key]);
            }
         }
         break;
       }
       canvas.renderAll();
     }
     redoStack.push(undoData);
    }
}

redo = function redo() {
    if(redoStack.length){
     var redoData = redoStack.pop();
     if(redoData && redoData.type){
       switch(redoData.type){
         case 'added':
         if(redoData.object){
           canvas.add(redoData.object);

         }
         break;
         case 'modified':
         var objectByName = canvas.getObjectByName(redoData.objectName);
         if(objectByName.length){
          	for(var key in redoData.newStage){
              objectByName[0].set(key, redoData.newStage[key]);
            }
         }
         break;
       }
       canvas.renderAll();
     }
     undoStack.push(redoData);
    }
}
clearcan = function clearcan() {
    canvas.clear().renderAll();
    canvas.counter=0;
    undoStack=[];
    redoStack=[];
    newleft = 0;
}

笔者由于只使用在一个项目中,故直接在插件写死交付。

/**
 * Initialization of the plugin
 */
fabric.Canvas.prototype._historyInit = function () {
    this.historyUndo = [];
    this.historyRedo = [];
    this.extraProps = ['selectable', 'editable','prodId','spaceProdId','picType','prodPicId','border','borderMsg'
    ,'afterStatus'];
    this.historyNextState = this._historyNext();

    this.on(this._historyEvents());
}

 

 

用户留言