Nano Hash - криптовалюты, майнинг, программирование

Как очистить свойства и события холста и добавить их обратно в 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.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" 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, верно? 16.12.2020
  • Да, я уже реализовал это частично, некоторые части работают, но не полностью, это проблема, с которой я сталкиваюсь в настоящее время. 16.12.2020

Ответы:


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

16.12.2020
  • Благодаря shahbazi, это работает и кажется лучшим подходом. Но выбранное событие после отмены не вызывает jsfiddle.net/fierce_trailblazer/ao7xc412/5 16.12.2020
  • Я думаю, что события нужно повторно инициализировать по-другому 16.12.2020
  • Неважно, третий параметр loadFromJson можно использовать для повторного запуска событий stackoverflow.com/questions/49697408/ 16.12.2020
  • Кроме того, вы можете прослушать событие selection:created и проверить, является ли объект тем, который вам нужен: fabricjs.com/events 16.12.2020
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..