[英]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.