Skip to content

Commit

Permalink
refactor(fabric-history): refactor the fabric-history and tuning the …
Browse files Browse the repository at this point in the history
…HistoryPlugin (#521)

* fix(plugin): fix the DringPlugin.ts that the cursor style grab and grabbing is not so much available

* refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin

* refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin

* refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin

* refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin

* refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin

* refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin

* refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin

* refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin

---------

Co-authored-by: GeorgeSmith <[email protected]>
  • Loading branch information
GeorgeSmith215 and GeorgeSmith authored Oct 26, 2024
1 parent ba4d092 commit e134fc0
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 35 deletions.
23 changes: 10 additions & 13 deletions packages/core/plugin/HistoryPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
/*
* @Author: 秦少卫
* @Date: 2023-06-20 13:06:31
* @LastEditors: 秦少卫
* @LastEditTime: 2024-07-12 21:35:16
* @LastEditors: George [email protected]
* @LastEditTime: 2024-10-15 09:35:35
* @Description: 历史记录插件
*/
import { fabric } from 'fabric';
Expand All @@ -17,12 +17,13 @@ declare module '@kuaitu/core' {
interface IEditor extends IPlugin {}
}

type callback = () => void;
type extendCanvas = {
undo: () => void;
redo: () => void;
undo: (callback?: callback) => void;
redo: (callback?: callback) => void;
clearHistory: () => void;
historyUndo: any[];
historyRedo: any[];
historyStack: any[];
historyIndex: number;
};

class HistoryPlugin implements IPluginTempl {
Expand All @@ -42,15 +43,15 @@ class HistoryPlugin implements IPluginTempl {
this.historyUpdate();
});
window.addEventListener('beforeunload', (e) => {
if (this.canvas.historyUndo.length > 0) {
if (this.canvas.historyStack.length > 0) {
(e || window.event).returnValue = '确认离开';
}
});
}

historyUpdate() {
const { historyUndo, historyRedo } = this.canvas;
this.editor.emit('historyUpdate', historyUndo.length, historyRedo.length);
const { historyStack, historyIndex } = this.canvas;
this.editor.emit('historyUpdate', historyIndex, historyStack.length - historyIndex);
}

// 导入模板之后,清理 History 缓存
Expand All @@ -61,10 +62,6 @@ class HistoryPlugin implements IPluginTempl {
}

undo() {
// if (this.canvas.historyUndo.length === 1) {
// // this.canvas.clearUndo();
// // this.editor.clear();
// }
this.canvas.undo();
this.historyUpdate();
}
Expand Down
80 changes: 58 additions & 22 deletions packages/core/utils/fabric-history.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*
* @Author: 秦少卫
* @Date: 2024-07-09 13:46:14
* @LastEditors: 秦少卫
* @LastEditTime: 2024-07-12 21:36:51
* @LastEditors: George [email protected]
* @LastEditTime: 2024-10-14 16:16:16
* @Description: file content
*/
/**
Expand Down Expand Up @@ -52,8 +52,9 @@ fabric.Canvas.prototype._historyEvents = function () {
* Initialization of the plugin
*/
fabric.Canvas.prototype._historyInit = function () {
this.historyUndo = [];
this.historyRedo = [];
this.historyStack = [];
this.historyIndex = 0;
this.historyMaxLength = 100;
this.extraProps = [
'id',
'gradientAngle',
Expand All @@ -65,6 +66,10 @@ fabric.Canvas.prototype._historyInit = function () {
'extension',
];
this.historyNextState = this._historyNext();
// 需要两次操作的标记,为true时表示当前操作记录为最新记录,需要撤销两步,因为最顶层的是当前的最新记录,undo一次后后置为false
this.isLatestHistoryState = true;
// 正在读取历史记录的标记,为 true 时不允许 undo/redo
this.isLoadingHistory = false;

this.on(this._historyEvents());
};
Expand All @@ -83,9 +88,19 @@ fabric.Canvas.prototype._historySaveAction = function (e) {
if (this.historyProcessing) return;
if (!e || (e.target && !e.target.excludeFromExport)) {
const json = this._historyNext();
this.historyUndo.push(json);
// 当前操作记录非最新记录,更新记录前需要校正历史索引,不然会丢失一个记录(undo时撤销了两次记录)。理论上不会超出历史记录上限,不过还是加了限制
!this.isLatestHistoryState &&
(this.isLatestHistoryState = true) &&
this.historyIndex < this.historyMaxLength &&
this.historyIndex++;
// 每次的最新操作都要清空历史索引之后的记录,防止redo旧记录,不然可能会redo之前某个阶段的操作记录
this.historyStack.length > this.historyIndex && this.historyStack.splice(this.historyIndex);
// 最多保存 historyMaxLength 条记录
if (this.historyIndex >= this.historyMaxLength) this.historyStack.shift();
this.historyIndex < this.historyMaxLength && this.historyIndex++;
this.historyStack.push(json);
this.historyNextState = this._historyNext();
this.fire('history:append', { json: json });
this.fire('history:append', { json });
}
};

Expand All @@ -95,19 +110,23 @@ fabric.Canvas.prototype._historySaveAction = function (e) {
* Also, pushes into redo history.
*/
fabric.Canvas.prototype.undo = function (callback) {
if (this.isLoadingHistory) return;
if (this.historyIndex <= 0) return;
// The undo process will render the new states of the objects
// Therefore, object:added and object:modified events will triggered again
// To ignore those events, we are setting a flag.
this.historyProcessing = true;

const history = this.historyUndo.pop();
// 当前操作记录为最新记录,需要撤销两步,因为最顶层的是当前的最新记录
this.isLatestHistoryState && this.historyIndex-- && (this.isLatestHistoryState = false);
const history = this.historyStack[--this.historyIndex];
if (history) {
// Push the current state to the redo history
this.historyRedo.push(this._historyNext());
this.historyNextState = history;
this._loadHistory(history, 'history:undo', callback);
} else {
console.log(1111);
this.historyIndex < 0 && (this.historyIndex = 0);
this.historyProcessing = false;
}
};
Expand All @@ -116,31 +135,40 @@ fabric.Canvas.prototype.undo = function (callback) {
* Redo to latest undo history.
*/
fabric.Canvas.prototype.redo = function (callback) {
if (this.isLoadingHistory) return;
if (this.historyIndex >= this.historyStack.length) return;
// The undo process will render the new states of the objects
// Therefore, object:added and object:modified events will triggered again
// To ignore those events, we are setting a flag.
this.historyProcessing = true;
const history = this.historyRedo.pop();
// 当前操作记录不是最新记录(被撤销过),需要恢复两步,抵消最初撤销时撤销两步的操作
!this.isLatestHistoryState && ++this.historyIndex && (this.isLatestHistoryState = true);
const history = this.historyStack[this.historyIndex];
if (history) {
// Every redo action is actually a new action to the undo history
this.historyUndo.push(this._historyNext());
this.historyNextState = history;
this._loadHistory(history, 'history:redo', callback);
this.historyIndex++;
} else {
this.historyProcessing = false;
}
};

// loadFromJSON 是异步操作,所以通过 isLoadingHistory = true 表示历史读取中,不可 undo/redo,
// 不然当页面复杂且快速 undo/redo 多次后,可能会在之前的历史上 redo/undo
fabric.Canvas.prototype._loadHistory = function (history, event, callback) {
this.isLoadingHistory = true;
var that = this;

history?.objects?.forEach((item) => {
if (item?.id === 'workspace') item.evented = false;
});
// 需要把历史记录中的 workspace 的 evented 属性设置为 false,否则会导致历史记录恢复后,鼠标悬浮 workspace 出现可操作的样式
const workspaceHistory = history.objects?.find((item) => item.id === 'workspace');
workspaceHistory && (workspaceHistory.evented = false);

this.loadFromJSON(history, function () {
that.renderAll();
that.fire(event);
that.historyProcessing = false;
that.isLoadingHistory = false;

if (callback && typeof callback === 'function') callback();
});
Expand All @@ -150,20 +178,28 @@ fabric.Canvas.prototype._loadHistory = function (history, event, callback) {
* Clear undo and redo history stacks
*/
fabric.Canvas.prototype.clearHistory = function (type) {
if (!type) {
this.historyUndo = [];
this.historyRedo = [];
const one = this.historyStack.pop();
if (!type || !one) {
this.historyStack = [];
this.historyIndex = 0;
this.fire('history:clear');
} else {
const one = this.historyUndo.pop();
this.historyUndo = [one];
this.historyRedo = [];
this.historyStack = [one];
this.historyIndex = 1;
this.fire('history:clear');
}
this.isLatestHistoryState = true;
};

fabric.Canvas.prototype.clearUndo = function () {
this.historyUndo = [];
this.historyStack.splice(this.historyIndex);
};

// 如果在做一些操作之后,需要撤销上一步的操作并刷新历史记录(想在监听modified事件后做些额外的操作并记录操作后的历史),可以调用这个方法
fabric.Canvas.prototype.refreshHistory = function () {
this.historyProcessing = false;
this.historyStack.splice(--this.historyIndex);
this._historySaveAction();
};

/**
Expand All @@ -180,14 +216,14 @@ fabric.Canvas.prototype.onHistory = function () {
*/

fabric.Canvas.prototype.canUndo = function () {
return this.historyUndo.length > 0;
return this.historyIndex > 0;
};

/**
* Check if there are actions that can be redone
*/
fabric.Canvas.prototype.canRedo = function () {
return this.historyRedo.length > 0;
return this.historyStack.length > this.historyIndex;
};

/**
Expand Down

0 comments on commit e134fc0

Please sign in to comment.