|
| 1 | +/* |
| 2 | + * @Author: 秦少卫 |
| 3 | + * @Date: 2024-07-09 13:46:14 |
| 4 | + * @LastEditors: 秦少卫 |
| 5 | + * @LastEditTime: 2024-07-09 14:27:27 |
| 6 | + * @Description: file content |
| 7 | + */ |
| 8 | +/** |
| 9 | + * Override the initialize function for the _historyInit(); |
| 10 | + */ |
| 11 | +import { fabric } from 'fabric'; |
| 12 | + |
| 13 | +fabric.Canvas.prototype.initialize = (function (originalFn) { |
| 14 | + return function (...args) { |
| 15 | + originalFn.call(this, ...args); |
| 16 | + this._historyInit(); |
| 17 | + return this; |
| 18 | + }; |
| 19 | +})(fabric.Canvas.prototype.initialize); |
| 20 | + |
| 21 | +/** |
| 22 | + * Override the dispose function for the _historyDispose(); |
| 23 | + */ |
| 24 | +fabric.Canvas.prototype.dispose = (function (originalFn) { |
| 25 | + return function (...args) { |
| 26 | + originalFn.call(this, ...args); |
| 27 | + this._historyDispose(); |
| 28 | + return this; |
| 29 | + }; |
| 30 | +})(fabric.Canvas.prototype.dispose); |
| 31 | + |
| 32 | +/** |
| 33 | + * Returns current state of the string of the canvas |
| 34 | + */ |
| 35 | +fabric.Canvas.prototype._historyNext = function () { |
| 36 | + return JSON.stringify(this.toDatalessJSON(this.extraProps)); |
| 37 | +}; |
| 38 | + |
| 39 | +/** |
| 40 | + * Returns an object with fabricjs event mappings |
| 41 | + */ |
| 42 | +fabric.Canvas.prototype._historyEvents = function () { |
| 43 | + return { |
| 44 | + 'object:added': (e) => this._historySaveAction(e), |
| 45 | + 'object:removed': (e) => this._historySaveAction(e), |
| 46 | + 'object:modified': (e) => this._historySaveAction(e), |
| 47 | + 'object:skewing': (e) => this._historySaveAction(e), |
| 48 | + }; |
| 49 | +}; |
| 50 | + |
| 51 | +/** |
| 52 | + * Initialization of the plugin |
| 53 | + */ |
| 54 | +fabric.Canvas.prototype._historyInit = function () { |
| 55 | + this.historyUndo = []; |
| 56 | + this.historyRedo = []; |
| 57 | + this.extraProps = [ |
| 58 | + 'id', |
| 59 | + 'gradientAngle', |
| 60 | + 'selectable', |
| 61 | + 'hasControls', |
| 62 | + 'linkData', |
| 63 | + 'editable', |
| 64 | + 'extensionType', |
| 65 | + 'extension', |
| 66 | + ]; |
| 67 | + this.historyNextState = this._historyNext(); |
| 68 | + |
| 69 | + this.on(this._historyEvents()); |
| 70 | +}; |
| 71 | + |
| 72 | +/** |
| 73 | + * Remove the custom event listeners |
| 74 | + */ |
| 75 | +fabric.Canvas.prototype._historyDispose = function () { |
| 76 | + this.off(this._historyEvents()); |
| 77 | +}; |
| 78 | + |
| 79 | +/** |
| 80 | + * It pushes the state of the canvas into history stack |
| 81 | + */ |
| 82 | +fabric.Canvas.prototype._historySaveAction = function (e) { |
| 83 | + if (this.historyProcessing) return; |
| 84 | + if (!e || (e.target && !e.target.excludeFromExport)) { |
| 85 | + const json = this._historyNext(); |
| 86 | + this.historyUndo.push(json); |
| 87 | + this.historyNextState = this._historyNext(); |
| 88 | + this.fire('history:append', { json: json }); |
| 89 | + } |
| 90 | +}; |
| 91 | + |
| 92 | +/** |
| 93 | + * Undo to latest history. |
| 94 | + * Pop the latest state of the history. Re-render. |
| 95 | + * Also, pushes into redo history. |
| 96 | + */ |
| 97 | +fabric.Canvas.prototype.undo = function (callback) { |
| 98 | + // The undo process will render the new states of the objects |
| 99 | + // Therefore, object:added and object:modified events will triggered again |
| 100 | + // To ignore those events, we are setting a flag. |
| 101 | + this.historyProcessing = true; |
| 102 | + |
| 103 | + const history = this.historyUndo.pop(); |
| 104 | + if (history) { |
| 105 | + // Push the current state to the redo history |
| 106 | + this.historyRedo.push(this._historyNext()); |
| 107 | + this.historyNextState = history; |
| 108 | + this._loadHistory(history, 'history:undo', callback); |
| 109 | + } else { |
| 110 | + console.log(1111); |
| 111 | + this.historyProcessing = false; |
| 112 | + } |
| 113 | +}; |
| 114 | + |
| 115 | +/** |
| 116 | + * Redo to latest undo history. |
| 117 | + */ |
| 118 | +fabric.Canvas.prototype.redo = function (callback) { |
| 119 | + // The undo process will render the new states of the objects |
| 120 | + // Therefore, object:added and object:modified events will triggered again |
| 121 | + // To ignore those events, we are setting a flag. |
| 122 | + this.historyProcessing = true; |
| 123 | + const history = this.historyRedo.pop(); |
| 124 | + if (history) { |
| 125 | + // Every redo action is actually a new action to the undo history |
| 126 | + this.historyUndo.push(this._historyNext()); |
| 127 | + this.historyNextState = history; |
| 128 | + this._loadHistory(history, 'history:redo', callback); |
| 129 | + } else { |
| 130 | + this.historyProcessing = false; |
| 131 | + } |
| 132 | +}; |
| 133 | + |
| 134 | +fabric.Canvas.prototype._loadHistory = function (history, event, callback) { |
| 135 | + var that = this; |
| 136 | + |
| 137 | + this.loadFromJSON(history, function () { |
| 138 | + that.renderAll(); |
| 139 | + that.fire(event); |
| 140 | + that.historyProcessing = false; |
| 141 | + |
| 142 | + if (callback && typeof callback === 'function') callback(); |
| 143 | + }); |
| 144 | +}; |
| 145 | + |
| 146 | +/** |
| 147 | + * Clear undo and redo history stacks |
| 148 | + */ |
| 149 | +fabric.Canvas.prototype.clearHistory = function () { |
| 150 | + this.historyUndo = []; |
| 151 | + this.historyRedo = []; |
| 152 | + this.fire('history:clear'); |
| 153 | +}; |
| 154 | + |
| 155 | +fabric.Canvas.prototype.clearUndo = function () { |
| 156 | + this.historyUndo = []; |
| 157 | +}; |
| 158 | + |
| 159 | +/** |
| 160 | + * On the history |
| 161 | + */ |
| 162 | +fabric.Canvas.prototype.onHistory = function () { |
| 163 | + this.historyProcessing = false; |
| 164 | + |
| 165 | + this._historySaveAction(); |
| 166 | +}; |
| 167 | + |
| 168 | +/** |
| 169 | + * Check if there are actions that can be undone |
| 170 | + */ |
| 171 | + |
| 172 | +fabric.Canvas.prototype.canUndo = function () { |
| 173 | + return this.historyUndo.length > 0; |
| 174 | +}; |
| 175 | + |
| 176 | +/** |
| 177 | + * Check if there are actions that can be redone |
| 178 | + */ |
| 179 | +fabric.Canvas.prototype.canRedo = function () { |
| 180 | + return this.historyRedo.length > 0; |
| 181 | +}; |
| 182 | + |
| 183 | +/** |
| 184 | + * Off the history |
| 185 | + */ |
| 186 | +fabric.Canvas.prototype.offHistory = function () { |
| 187 | + this.historyProcessing = true; |
| 188 | +}; |
0 commit comments