如何清除画布属性和事件并将其添加回fabricjs?
Posted
技术标签:
【中文标题】如何清除画布属性和事件并将其添加回fabricjs?【英文标题】:How to clear canvas properties and events and add it back in fabricjs? 【发布时间】:2021-03-26 23:19:08 【问题描述】:上下文:
我有一个用例,我需要从堆栈中获取旧画布并将其分配给 dom 中当前活动的画布。我目前面临的问题是画布属性(例如背景颜色、高度等)被替换并正确显示,但如果画布内的对象,属性和事件看起来像是被替换但没有显示在活动中画布(DOM)。
注意:我这里没有使用fabric的撤消/重做的选项。
我试图在我尝试执行以下操作的 sn-p 中重新创建问题。
第 1 步:我正在使用 addTextBox 方法创建具有默认属性的画布和对象,一旦应用了默认属性,我会将画布和文本框对象存储在一个称为状态的变量中以进行备份。
第 2 步:
在 AddHelloText Click(Button) 上,我正在推送已记录的状态 在上一步中撤消堆栈。
之后,我将“hello”分配给文本框并“更改背景颜色” 变红”。
第 3 步: 在 Undo Click(Button) 上,我从 undoStack 获取 canvasOb 并将 i 分配给 canvas(活动画布)。
在这一步中,当我撤消时,画布上的值/事件应该是存储在 undoStack 中的备份画布,但它的值不正确。 简单来说,画布背景应该是“蓝色”,文本框对象应该有“默认文本”,即使我点击 在文本框上它应该有背景“蓝色”和文本 “默认文本”
这是我目前面临的两个问题。
只有背景更新,文本对象保持不变。
单击边界框(文本框)时,会显示画布的另一个实例(具有 step2 值的实例)
不确定我应该如何进一步进行。
任何建议都会很有帮助。
var canvas = new fabric.Canvas("c");
var t1 = null;
var state = ;
const addTextBox=(canvasParam)=>
t1 = new fabric.Textbox('Default text',
width: 100,
top: 5,
left: 5,
fontSize: 16,
textAlign: 'center',
fill: '#ffffff',
);
canvas.on('selected', () =>
canvas.clearContext(canvas.contextTop);
);
canvas.setBackgroundColor('blue');
canvas.add(t1);
state=id:1,canvasOb:canvas,t1Backup:t1;
addTextBox(canvas);
var undoStack =[];
//Update the text to hello and change canvas background to red
$('#addHello').on('click', function()
undoStack.push(state:_.cloneDeep(state))
canvas.setBackgroundColor('red');
t1.text="hello red"
canvas.renderAll();
)
//apply previous canvas stored in the stack
$('#undo').on('click', function()
console.log("TextBox value stored in undo stack: ",undoStack[0].state.canvasOb.getObjects()[0].text);
console.log("TextBox value stored in undo stack: ",undoStack[0].state.t1Backup.text);
canvas = undoStack[0].state.canvasOb;
console.log("Textbox value that should be displayed currently instead of 'hello red':",canvas.getObjects()[0].text);
canvas.renderAll();
)
body
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
#c
box-shadow: 0 0 20px 0px #9090908a;
border-radius: 1rem;
//padding:.5rem;
#app-container
height: 30vh;
width: 30vw;
<script src="https://unpkg.com/lodash@4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
<html><body><div id="app-container">
<canvas id="c" ></canvas>
<button id="addHello" class="button">Add hello</button>
<button id="undo" class="button">Undo</button>
</div></body></html>
【问题讨论】:
您好,我相信您想在不使用原生 fabric.js 撤消/重做 API 的情况下实现撤消/重做选项,对吧? 是的,我已经部分实现了,有些部分工作但不完全,以上是我目前面临的问题。 【参考方案1】:即使您将其引用保存在您的状态对象中,您仍在动态更改画布对象。因此,当您更新文本或更改画布的背景颜色等时,实际上您正在更改保存的状态,因为到目前为止您所做的只是保存对 fabric.js 画布object
的引用。
这篇文章可能很有趣:
Reference vs Primitive values in javascript
完成您想要实现的目标的最佳方法(在我看来)是使用fabric.js toJSON
方法并将状态保存为JSON
,然后在需要时使用loadFromJSON
再次检索它。
这是一个例子:
var canvas = new fabric.Canvas('c');
var t1 = null;
var undoStack = [];
// Whenever you make a change and then you want to save it as a state
const addNewState = () =>
var canvasObject = canvas.toJSON();
undoStack.push(JSON.stringify(canvasObject));
;
const initCanvas = () =>
t1 = new fabric.Textbox('Default text',
width: 100,
top: 5,
left: 5,
fontSize: 16,
textAlign: 'center',
fill: '#ffffff',
);
canvas.on('selected', () =>
canvas.clearContext(canvas.contextTop);
);
canvas.setBackgroundColor('blue');
canvas.add(t1);
addNewState(); // Our first state
;
// Init canvas with default parameters
initCanvas(canvas);
const retrieveLastState = () =>
var latestState = undoStack[undoStack.length - 1]; // Get last state
var parsedJSON = JSON.parse(latestState);
canvas.loadFromJSON(parsedJSON);
;
// Update the text to hello and change canvas background to red
$('#addHello').on('click', function ()
canvas.setBackgroundColor('red');
t1.text = 'hello red';
canvas.renderAll();
);
// apply previous canvas stored in the stack
// Retrieve the very last state
$('#undo').on('click', function ()
retrieveLastState();
canvas.renderAll();
);
body
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
#c
box-shadow: 0 0 20px 0px #9090908a;
border-radius: 1rem;
#app-container
height: 30vh;
width: 30vw;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app-container">
<canvas id="c" ></canvas>
<button id="addHello" class="button">Add hello</button>
<button id="undo" class="button">Undo</button>
</div>
<script src="https://unpkg.com/lodash@4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</body>
</html>
但是,下次您单击#addHello
按钮并尝试再次撤消它时,它不会起作用。原因是我们试图访问t1
变量,它是第一个画布上的一个fabric.js 对象。解决方案是为添加到画布的每个对象分配一个 id,以便您可以再次检索它们(用于修改、删除等)。这会让事情变得更复杂,所以我没有把它放在这里。
【讨论】:
感谢 shahbazi 这行得通,似乎是一种更好的方法。但是撤消后的“选定”事件不会调用jsfiddle.net/fierce_trailblazer/ao7xc412/5 我认为事件需要以不同的方式重新初始化 Nevermind loadFromJson 第三个参数可以用来重新初始化事件***.com/questions/49697408/… 或者,您可以监听selection:created
事件,并检查对象是否是您想要的对象:fabricjs.com/events以上是关于如何清除画布属性和事件并将其添加回fabricjs?的主要内容,如果未能解决你的问题,请参考以下文章