簡體   English   中英

使用stateProperties和hasStateChanged在fabric.js中實現undo / redo

[英]Using stateProperties and hasStateChanged to implement undo / redo in fabric.js

編輯:這個問題的范圍有所改變。 請參閱下面的更新。

我一直在為fabric.js做一些撤銷/重做(見 小提琴 )。 雖然相當天真,但它大部分都在工作(用於添加/移除/移動或調整單個對象的大小或添加/刪除對象組),但不適用於移動或調整對象組。 在小提琴中,注意onObjectSelected()函數的控制台輸出。

要查看我的意思,請在小提琴畫布上繪制一些對象,然后單獨移動或調整它們。 撤消/重做按預期工作。 但是,當選擇並移動組時,我看不到如何檢索組內對象的更新位置,這意味着撤消/重做無法恢復正確的值。

 
 
 
 
  
  
  // onObjectSelected function quoted here to satisfy stackoverflow // question requirements. See full jsfiddle for context. for (i in canvas.getObjects()) { if (canvas.item(i).active === true ) { console.log(canvas.item(i)); selectedObject.push({ "itemNum" : i, "svdObject" : fabric.util.object.clone(canvas.item(i)) }); } }
 
 
  

原因似乎是當作為一組移動或調整大小時,對象位置/比例不會更新。 我嘗試了各種各樣的東西,包括為所有對象運行setCoords(),但這沒有幫助。 所以如果有人能夠發現我做錯了什么,或者知道如何解決這個問題,我會很感激。

編輯:為了澄清,這只是一個普通的撤銷/重做系統,當用戶修改它們時,使用兩個數組來存儲畫布上對象的屬性。 單擊撤消或重做時,屬性將應用於畫布上的對象。 我遇到的問題是,當選擇對象 並隨后進行修改時,我不知道如何捕獲某些屬性,例如組中對象的位置,因為組內對象的屬性是由於某種原因將對象修改為組時未更新。

更新 :我已經了解到,當對象位於用戶選擇的組中時,對象位置將相對於其所在的組進行記錄,而不再是畫布,這是有意義的。 因此,當處理組中的對象時, 其左/頂部坐標添加到組左/頂部坐標以計算對象相對於畫布的坐標。 scaleX / Y應乘以group scaleX / Y.

更新 :我已經管理好讓我做我想做的事(見新小提琴 )。 我已經了解了fabric的'stateful'標志,stateProperties數組和hasStateChanged方法,這將簡化事情。 這些文檔很少,到目前為止我還沒有成功地在這個解決方案中使用它們。 使用這些的使用技巧或示例代碼將不勝感激。 具體來說,我希望能夠控制保存哪些屬性 ,因為我不需要保存所有可更改的屬性。

onObjectSelected目前看起來像這樣:

 function onObjectSelected() { selectedObject = []; for (i in canvas.getObjects()) { if (canvas.item(i).active === true) { // shft-ctrl-j to see item properties on click (chrome) console.log(canvas.item(i)); // objects can be flipped, but not groups var groupLeft = 0; var groupTop = 0; var groupScaleX = 1; var groupScaleY = 1; var groupAngle = 0; // if it's a group, add group coords also if (typeof canvas.item(i).group != "undefined") { var groupLeft = canvas.item(i).group.left; var groupTop = canvas.item(i).group.top; var groupScaleX = canvas.item(i).group.scaleX; var groupScaleY = canvas.item(i).group.scaleY; var groupAngle = canvas.item(i).group.angle; } selectedObject.push({ "itemNum": i, "left": canvas.item(i).left + groupLeft, "top": canvas.item(i).top + groupTop, "scaleX": canvas.item(i).scaleX * groupScaleX, "scaleY": canvas.item(i).scaleY * groupScaleY, "angle": canvas.item(i).angle + groupAngle, "flipX": canvas.item(i).flipX, "flipY": canvas.item(i).flipY }); } } }; 

Fabricjs默認不支持自動縮放或定位。 支持這一點的唯一方法是實現自己的擴展/定位機制。 我也嘗試過很多東西,但這些線條目前效果最好。

所以基本上,請在你的js中添加這些功能:

function prepareRatio(o){
    saveRatio(o);
    o.on('modified', function(e){
        saveRatio(o);
    });
}

function restoreRatio(o){
    o.set({
        left: o._ratio._left * _cv.width,
        top: o._ratio._top * _cv.height,
        width: o._ratio._width * _cv.width,
        height: o._ratio._height * _cv.height
    });

    o.setCoords();
}

function saveRatio(obj){
    obj._ratio = { 
        _left: obj.left / _cv.width,
        _top: obj.top / _cv.height,
        _width: obj.width / _cv.width,
        _height: obj.height / _cv.height
    };
}

我在這里使用了2個自定義變量,其中_cv是用於存儲目標畫布的寬度和高度的簡化結構,_ratio用於每個對象(常量)比值。

在創建對象或調整畫布大小時明智地使用它們:

fabric.Image.fromURL('xxxx.png', function(img) {

    img.set({
        // TODO: give object width and height, left and top
    });

    // save ratio once you create an object
    prepareRatio(img);

    canvas.add(img);

    // OPTIONAL: add your own codes
});

function redraw() {

    // TODO: resize your canvas as you want

    _cv = {
        width: canvas.getWidth(),
        height: canvas.getHeight()
    };

    canvas.forEachObject(function(obj) {
        // restore ratio every time when you resize your canvas
        restoreRatio(obj);
    });
}

window.addEventListener('resize', redraw, false);

這看起來有點長,但事實上非常簡單明了。 我很確定這會立即在你身邊發揮作用。 希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM