-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(fabric-history): refactor the fabric-history and tuning the …
…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
1 parent
ba4d092
commit e134fc0
Showing
2 changed files
with
68 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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'; | ||
|
@@ -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 { | ||
|
@@ -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 缓存 | ||
|
@@ -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(); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
*/ | ||
/** | ||
|
@@ -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', | ||
|
@@ -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()); | ||
}; | ||
|
@@ -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 }); | ||
} | ||
}; | ||
|
||
|
@@ -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; | ||
} | ||
}; | ||
|
@@ -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(); | ||
}); | ||
|
@@ -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(); | ||
}; | ||
|
||
/** | ||
|
@@ -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; | ||
}; | ||
|
||
/** | ||
|