Fabri cjs - Реализация отмен / повторов на полотнах - PullRequest
0 голосов
/ 27 апреля 2020

Я новичок ie в vue и Фабри cjs и в настоящее время работаю над сложным приложением, которое работает с большим объемом данных. У меня есть несколько полотен с различными объектами, которые могут меняться в зависимости от взаимодействия с пользователем. Все изменения / объекты хранятся в массиве объектов

Демо: https://prkos.csb.app/ enter image description here

Я пытаюсь реализовать отменить / повторить в моем приложении. Мне трудно понять подход fabri cjs отменить / повторить в ответе ниже (ссылка)

Функция отмены-возврата в Fabri c. js

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

Я испробовал нижеприведенный подход не-fabri c, где отмена, повтор работает с индексом истории, который будет изменяться на основе при отмене (указатель приращения), концепция повторения (указатель приращения).

Основываясь на этом подходе, я называю мутацию, в которой

apply(state,actiontype){
if(actiontype==undo){
           remove the respective objects
           pop(data) //pops the data out of other places in the application not the history
           historyindex++;
}else if(actiontype==redo){
           get the data from history
           unshift(data);
           historyindex–-;
}
}

Я чувствую, что это не самый эффективный способ выполнения отменить / повторить операции, так как она включает в себя клонирование объектов и даже должна обрабатывать огромные наборы данных. Что может привести к зависанию приложения. Любые предложения будут очень полезны.

Код: (несколько полотен) https://codesandbox.io/s/test-project-prkos?file= / src / components / App. vue

Отредактировано: я обновил пример с функциями отмены / повторения, использованной библиотекой истории fabri c, все еще пытающейся найти лучший подход.

1 Ответ

0 голосов
/ 29 апреля 2020

Я думаю, вам нужно использовать шаблон команды для этого. Это будет более эффективно, чем использование всех данных json. Для этого вам необходимо реализовать следующий подход:

  1. Создать класс для хранения истории. Это может выглядеть так
class CommandHistory {
  commands = [];
  index = 0;
  getIndex() {
    return this.index;
  }
  back() {
    if (this.index > 0) {
      let command = this.commands[--this.index];
      command.undo();
    }
    return this;
  }
  forward() {
    if (this.index < this.commands.length) {
      let command = this.commands[this.index++];
      command.execute();
    }
    return this;
  }
  add(command) {
    if (this.commands.length) {
      this.commands.splice(this.index, this.commands.length - this.index);
    }
    this.commands.push(command);
    this.index++;
    return this;
  }
  clear() {
    this.commands.length = 0;
    this.index = 0;
    return this;
  }
}

// use when you init your Canvas, like this.history = new CommandHistory();
Затем вы должны реализовать классы команд для своих команд.

Для добавления объекта

class AddCommand {
  constructor(receiver, controller) {
    this.receiver = receiver;
    this.controller = controller;
  }
  execute() {
    this.controller.addObject(this.receiver);
  }
  undo() {
    this.controller.removeObject(this.receiver);
  }
}

// When you will add object on your canvas invoke also this.history.add(new AddCommand(object, controller))

Для удаления объекта

class RemoveCommand {
  constructor(receiver, controller) {
    this.receiver = receiver;
    this.controller = controller;
  }
  execute() {
    this.controller.removeObject(this.receiver);
  }
  undo() {
    this.controller.addObject(this.receiver);
  }
}

Фабри c. js имеет метод saveState для каждого объекта http://fabricjs.com/docs/fabric.Object.html#saveState. И вы можете использовать его для реализации команды transform, которая будет добавлена ​​к объекту истории, когда вы измените свой объект fabri c на холсте.

class TransformCommand {
  constructor(receiver, options = {}) {
    this.receiver = receiver;
    this._initStateProperties(options);

    this.state = {};
    this.prevState = {};

    this._saveState();
    this._savePrevState();
  }
  execute() {
    this._restoreState();
    this.receiver.setCoords();
  }
  undo() {
    this._restorePrevState();
    this.receiver.setCoords();
  }
  // private
  _initStateProperties(options) {
    this.stateProperties = this.receiver.stateProperties;
    if (options.stateProperties && options.stateProperties.length) {
      this.stateProperties.push(...options.stateProperties);
    }
  }
  _restoreState() {
    this._restore(this.state);
  }
  _restorePrevState() {
    this._restore(this.prevState);
  }
  _restore(state) {
    this.stateProperties.forEach((prop) => {
      this.receiver.set(prop, state[prop]);
    });
  }
  _saveState() {
    this.stateProperties.forEach((prop) => {
      this.state[prop] = this.receiver.get(prop);
    });
  }
  _savePrevState() {
    if (this.receiver._stateProperties) {
      this.stateProperties.forEach((prop) => {
        this.prevState[prop] = this.receiver._stateProperties[prop];
      });
    }
  }
}

Теперь вы можете добавлять свои команды в свою историю и выполнить или отменить их.

...