Как очистить свойства и события холста и добавить их обратно в Fabricjs?

Контекст:

У меня есть вариант использования, когда мне нужно получить старый холст из стека и назначить его текущему активному холсту в dom. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что свойства холста (например, backgroundColor, высота и т. д.) заменяются и отображаются правильно, но в случае объектов на холсте свойства и события выглядят так, как будто они заменяются, но не отображаются в активном холст(ДОМ).

Примечание. У меня нет возможности использовать здесь отмену/возврат ткани.

Я попытался воссоздать проблему во фрагменте, где я пытаюсь сделать следующее.

Шаг 1: я создаю холст и объекты со свойствами по умолчанию, используя метод addTextBox, после применения свойств по умолчанию я сохраняю объект холста и текстового поля в переменной, называемой состоянием для резервного копирования.

Шаг 2:

  • при нажатии AddHelloText (кнопке) я нажимаю состояние, которое было записано на предыдущем шаге, чтобы отменить стек.

  • После этого я назначаю «привет» текстовому полю и «меняю цвет фона до красного».

Шаг 3: при нажатии кнопки отмены (кнопка) я получаю canvasOb из undoStack и назначаю i холсту (активному холсту).

На этом шаге, когда я делаю отмену, значения/события на холсте должны относиться к резервному холсту, который был сохранен в стеке отмены, но вместо этого он имеет неверные значения. Проще говоря, фон холста должен быть «синим», а объект текстового поля должен иметь «текст по умолчанию», даже когда я нажимаю в текстовом поле предполагается, что фон "синий" и текст как «Текст по умолчанию»

Это две проблемы, с которыми я сталкиваюсь в настоящее время.

  • Обновляется только фон, а текстовый объект остается прежним.

  • При нажатии на ограничивающую рамку (текстовое поле) отображается другой экземпляр холста (тот, который имеет значения шага 2).

Не уверен, как именно мне следует действовать дальше.

Любые предложения будут действительно полезны.

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.info("TextBox value stored in undo stack: ",undoStack[0].state.canvasOb.getObjects()[0].text);
    console.info("TextBox value stored in undo stack: ",undoStack[0].state.t1Backup.text);
    canvas = undoStack[0].state.canvasOb;
    console.info("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" width = "200" height = "300"></canvas>
  <button id = "addHello" class = "button">Add hello</button>
  <button id = "undo" class = "button">Undo</button>
 </div></body></html>

Здравствуйте, я полагаю, вы хотите реализовать опцию отмены/повторения без использования собственного API отмены/повторения Fabric.js, верно?

M.A Shahbazi 16.12.2020 10:59

Да, я уже реализовал это частично, некоторые части работают, но не полностью, это проблема, с которой я сталкиваюсь в настоящее время.

A.D 16.12.2020 11:06
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
2
1 157
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы изменяете объект холста на лету, даже если сохраняете его ссылку внутри своего объекта состояния. Таким образом, когда вы обновляете текст или меняете цвет фона холста и т. д., вы фактически меняете свое сохраненное состояние, потому что все, что вы сделали до сих пор, — это сохранили ссылку на холст fabric.js object.

Эта статья может быть интересна: Справочные и примитивные значения в 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" width = "200" height = "300"></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 на самом первом холсте. Решением было бы назначить идентификатор каждому объекту, который вы добавляете на холст, чтобы вы могли снова получить их (для изменения, удаления и т. д.). Это сильно усложнило бы задачу, поэтому я не привожу это здесь.

Благодаря shahbazi, это работает и кажется лучшим подходом. Но «выбранное» событие после отмены не вызывается jsfiddle.net/fierce_trailblazer/ao7xc412/5

A.D 16.12.2020 12:54

Я думаю, что события нужно повторно инициализировать по-другому

A.D 16.12.2020 12:55

Неважно, третий параметр loadFromJson можно использовать для повторной инициализации событий stackoverflow.com/questions/49697408/…

A.D 16.12.2020 13:12

Кроме того, вы можете прослушать событие selection:created и проверить, является ли объект тем, который вам нужен: Fabricjs.com/events

M.A Shahbazi 16.12.2020 13:13

Другие вопросы по теме