From 2eb339470345a47fd3155f9af398d35d01db4963 Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Mon, 12 Aug 2024 17:35:45 +0800 Subject: [PATCH 01/11] fix(plugin): fix the DringPlugin.ts that the cursor style grab and grabbing is not so much available --- packages/core/plugin/DringPlugin.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/core/plugin/DringPlugin.ts b/packages/core/plugin/DringPlugin.ts index 7feafd8e..30e8e516 100644 --- a/packages/core/plugin/DringPlugin.ts +++ b/packages/core/plugin/DringPlugin.ts @@ -26,13 +26,13 @@ export class DringPlugin implements IPluginTempl { startDring() { this.dragMode = true; - this.canvas.defaultCursor = 'grab'; + this.canvas.setCursor('grab'); this.editor.emit('startDring'); this.canvas.renderAll(); } endDring() { this.dragMode = false; - this.canvas.defaultCursor = 'default'; + this.canvas.setCursor('default'); this.canvas.isDragging = false; this.editor.emit('endDring'); this.canvas.renderAll(); @@ -44,7 +44,7 @@ export class DringPlugin implements IPluginTempl { this.canvas.on('mouse:down', function (this: ExtCanvas, opt) { const evt = opt.e; if (evt.altKey || This.dragMode) { - This.canvas.defaultCursor = 'grabbing'; + This.canvas.setCursor('grabbing'); This.canvas.discardActiveObject(); This._setDring(); this.selection = false; @@ -56,9 +56,10 @@ export class DringPlugin implements IPluginTempl { }); this.canvas.on('mouse:move', function (this: ExtCanvas, opt) { + This.dragMode && This.canvas.setCursor('grab'); if (this.isDragging) { This.canvas.discardActiveObject(); - This.canvas.defaultCursor = 'grabbing'; + This.canvas.setCursor('grabbing'); const { e } = opt; if (!this.viewportTransform) return; const vpt = this.viewportTransform; @@ -80,14 +81,13 @@ export class DringPlugin implements IPluginTempl { obj.selectable = true; } }); - This.canvas.defaultCursor = 'default'; + This.dragMode && This.canvas.setCursor('grab'); this.requestRenderAll(); }); } _setDring() { this.canvas.selection = false; - this.canvas.defaultCursor = 'grab'; this.canvas.getObjects().forEach((obj) => { obj.selectable = false; }); From 1d1129e243c1fd58374aa3bb61bb45228943bdfe Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Fri, 11 Oct 2024 13:34:16 +0800 Subject: [PATCH 02/11] refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin --- packages/core/plugin/HistoryPlugin.ts | 23 +++++----- packages/core/utils/fabric-history.js | 61 ++++++++++++++++++--------- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/packages/core/plugin/HistoryPlugin.ts b/packages/core/plugin/HistoryPlugin.ts index 2993abcb..5c68b03a 100644 --- a/packages/core/plugin/HistoryPlugin.ts +++ b/packages/core/plugin/HistoryPlugin.ts @@ -2,21 +2,22 @@ /* * @Author: 秦少卫 * @Date: 2023-06-20 13:06:31 - * @LastEditors: 秦少卫 - * @LastEditTime: 2024-07-12 21:35:16 + * @LastEditors: George GeorgeSmith163@163.com + * @LastEditTime: 2024-10-11 11:11:11 * @Description: 历史记录插件 */ import { fabric } from 'fabric'; import Editor from '../Editor'; import '../utils/fabric-history.js'; +type callback = () => void; type IEditor = Editor; 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 { @@ -36,15 +37,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 缓存 @@ -55,10 +56,6 @@ class HistoryPlugin implements IPluginTempl { } undo() { - // if (this.canvas.historyUndo.length === 1) { - // // this.canvas.clearUndo(); - // // this.editor.clear(); - // } this.canvas.undo(); this.historyUpdate(); } diff --git a/packages/core/utils/fabric-history.js b/packages/core/utils/fabric-history.js index 6087c45f..9bde2d0b 100644 --- a/packages/core/utils/fabric-history.js +++ b/packages/core/utils/fabric-history.js @@ -1,8 +1,8 @@ /* * @Author: 秦少卫 * @Date: 2024-07-09 13:46:14 - * @LastEditors: 秦少卫 - * @LastEditTime: 2024-07-12 21:36:51 + * @LastEditors: George GeorgeSmith163@163.com + * @LastEditTime: 2024-10-11 11:11:11 * @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,8 @@ fabric.Canvas.prototype._historyInit = function () { 'extension', ]; this.historyNextState = this._historyNext(); + // 需要两次操作的标记,为true时表示当前操作记录为最新记录,需要做两步操作,因为最顶层的是当前的最新记录 + this.isLatestHistoryState = true; this.on(this._historyEvents()); }; @@ -83,9 +86,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); + // 当前操作记录非最新记录,更新记录前需要校正历史索引,不然会丢失一个记录。理论上不会超出历史记录上限,不过还是加了限制 + !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 }); } }; @@ -100,14 +113,16 @@ fabric.Canvas.prototype.undo = function (callback) { // 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; } }; @@ -120,12 +135,14 @@ fabric.Canvas.prototype.redo = function (callback) { // 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; } @@ -134,6 +151,10 @@ fabric.Canvas.prototype.redo = function (callback) { fabric.Canvas.prototype._loadHistory = function (history, event, callback) { var that = this; + // 需要把历史记录中的 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); @@ -147,20 +168,22 @@ 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 = []; + this.historyIndex = 0; }; /** @@ -177,14 +200,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; }; /** From 6c1f6c63d7fa073264077e586bdc588bbb4d54da Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Mon, 14 Oct 2024 11:51:57 +0800 Subject: [PATCH 03/11] refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin --- packages/core/utils/fabric-history.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/core/utils/fabric-history.js b/packages/core/utils/fabric-history.js index 9bde2d0b..eab4a9bd 100644 --- a/packages/core/utils/fabric-history.js +++ b/packages/core/utils/fabric-history.js @@ -2,13 +2,14 @@ * @Author: 秦少卫 * @Date: 2024-07-09 13:46:14 * @LastEditors: George GeorgeSmith163@163.com - * @LastEditTime: 2024-10-11 11:11:11 + * @LastEditTime: 2024-10-14 11:33:33 * @Description: file content */ /** * Override the initialize function for the _historyInit(); */ import { fabric } from 'fabric'; +import { debounce } from 'lodash-es'; fabric.Canvas.prototype.initialize = (function (originalFn) { return function (...args) { @@ -66,7 +67,7 @@ fabric.Canvas.prototype._historyInit = function () { 'extension', ]; this.historyNextState = this._historyNext(); - // 需要两次操作的标记,为true时表示当前操作记录为最新记录,需要做两步操作,因为最顶层的是当前的最新记录 + // 需要两次操作的标记,为true时表示当前操作记录为最新记录,需要撤销两步,因为最顶层的是当前的最新记录,undo一次后后置为false this.isLatestHistoryState = true; this.on(this._historyEvents()); @@ -86,7 +87,7 @@ fabric.Canvas.prototype._historySaveAction = function (e) { if (this.historyProcessing) return; if (!e || (e.target && !e.target.excludeFromExport)) { const json = this._historyNext(); - // 当前操作记录非最新记录,更新记录前需要校正历史索引,不然会丢失一个记录。理论上不会超出历史记录上限,不过还是加了限制 + // 当前操作记录非最新记录,更新记录前需要校正历史索引,不然会丢失一个记录(undo时撤销了两次记录)。理论上不会超出历史记录上限,不过还是加了限制 !this.isLatestHistoryState && (this.isLatestHistoryState = true) && this.historyIndex < this.historyMaxLength && @@ -108,12 +109,13 @@ fabric.Canvas.prototype._historySaveAction = function (e) { * Also, pushes into redo history. */ fabric.Canvas.prototype.undo = function (callback) { + 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; - // 当前操作记录为最新记录,需要恢复两步,因为最顶层的是当前的最新记录 + // 当前操作记录为最新记录,需要撤销两步,因为最顶层的是当前的最新记录 this.isLatestHistoryState && --this.historyIndex && (this.isLatestHistoryState = false); const history = this.historyStack[--this.historyIndex]; if (history) { @@ -131,6 +133,7 @@ fabric.Canvas.prototype.undo = function (callback) { * Redo to latest undo history. */ fabric.Canvas.prototype.redo = function (callback) { + 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. @@ -148,10 +151,11 @@ fabric.Canvas.prototype.redo = function (callback) { } }; -fabric.Canvas.prototype._loadHistory = function (history, event, callback) { +// loadFromJSON 是异步操作,所以加了防抖,不然快速 undo/redo 多次后,可能会在之前的历史上 redo/undo +fabric.Canvas.prototype._loadHistory = debounce(function (history, event, callback) { var that = this; - // 需要把历史记录中的 workspace 的 evented 属性设置为 false,否则会导致历史记录恢复后,鼠标悬浮 workspace 会出现可操作的样式 + // 需要把历史记录中的 workspace 的 evented 属性设置为 false,否则会导致历史记录恢复后,鼠标悬浮 workspace 出现可操作的样式 const workspaceHistory = history.objects?.find((item) => item.id === 'workspace'); workspaceHistory && (workspaceHistory.evented = false); @@ -162,7 +166,7 @@ fabric.Canvas.prototype._loadHistory = function (history, event, callback) { if (callback && typeof callback === 'function') callback(); }); -}; +}, 100); /** * Clear undo and redo history stacks @@ -182,8 +186,13 @@ fabric.Canvas.prototype.clearHistory = function (type) { }; fabric.Canvas.prototype.clearUndo = function () { - this.historyStack = []; - this.historyIndex = 0; + this.historyStack.splice(this.historyIndex); +}; + +// 如果在做一些操作之后,需要撤销上一步的操作并刷新历史记录(想在监听modified事件后做些额外的操作并记录操作后的历史),可以调用这个方法 +fabric.Canvas.prototype.refreshHistory = function () { + this.historyStack.splice(--this.historyIndex); + this._historySaveAction(); }; /** From 1207326d7c706a0576f6928af63cc817e85f87d7 Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Mon, 14 Oct 2024 14:45:39 +0800 Subject: [PATCH 04/11] refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin --- packages/core/utils/fabric-history.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/utils/fabric-history.js b/packages/core/utils/fabric-history.js index eab4a9bd..1c9ba590 100644 --- a/packages/core/utils/fabric-history.js +++ b/packages/core/utils/fabric-history.js @@ -151,7 +151,7 @@ fabric.Canvas.prototype.redo = function (callback) { } }; -// loadFromJSON 是异步操作,所以加了防抖,不然快速 undo/redo 多次后,可能会在之前的历史上 redo/undo +// loadFromJSON 是异步操作,所以加了防抖,不然当页面复杂且快速 undo/redo 多次后,可能会在之前的历史上 redo/undo fabric.Canvas.prototype._loadHistory = debounce(function (history, event, callback) { var that = this; @@ -166,7 +166,7 @@ fabric.Canvas.prototype._loadHistory = debounce(function (history, event, callba if (callback && typeof callback === 'function') callback(); }); -}, 100); +}, 50); /** * Clear undo and redo history stacks From 29dd013e8568929a0b174840cdb3e5bc5d90fbbd Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Mon, 14 Oct 2024 16:50:57 +0800 Subject: [PATCH 05/11] refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin --- packages/core/utils/fabric-history.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/core/utils/fabric-history.js b/packages/core/utils/fabric-history.js index 1c9ba590..7c6a1fd7 100644 --- a/packages/core/utils/fabric-history.js +++ b/packages/core/utils/fabric-history.js @@ -2,7 +2,7 @@ * @Author: 秦少卫 * @Date: 2024-07-09 13:46:14 * @LastEditors: George GeorgeSmith163@163.com - * @LastEditTime: 2024-10-14 11:33:33 + * @LastEditTime: 2024-10-14 16:16:16 * @Description: file content */ /** @@ -69,6 +69,8 @@ fabric.Canvas.prototype._historyInit = function () { this.historyNextState = this._historyNext(); // 需要两次操作的标记,为true时表示当前操作记录为最新记录,需要撤销两步,因为最顶层的是当前的最新记录,undo一次后后置为false this.isLatestHistoryState = true; + // 正在读取历史记录的标记,为 true 时不允许 undo/redo + this.isLoadingHistory = false; this.on(this._historyEvents()); }; @@ -109,6 +111,7 @@ 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 @@ -133,6 +136,7 @@ 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 @@ -151,8 +155,10 @@ fabric.Canvas.prototype.redo = function (callback) { } }; -// loadFromJSON 是异步操作,所以加了防抖,不然当页面复杂且快速 undo/redo 多次后,可能会在之前的历史上 redo/undo -fabric.Canvas.prototype._loadHistory = debounce(function (history, event, callback) { +// loadFromJSON 是异步操作,所以通过 isLoadingHistory = true 表示历史读取中,不可 undo/redo, +// 不然当页面复杂且快速 undo/redo 多次后,可能会在之前的历史上 redo/undo +fabric.Canvas.prototype._loadHistory = function (history, event, callback) { + this.isLoadingHistory = true; var that = this; // 需要把历史记录中的 workspace 的 evented 属性设置为 false,否则会导致历史记录恢复后,鼠标悬浮 workspace 出现可操作的样式 @@ -163,10 +169,11 @@ fabric.Canvas.prototype._loadHistory = debounce(function (history, event, callba that.renderAll(); that.fire(event); that.historyProcessing = false; + that.isLoadingHistory = false; if (callback && typeof callback === 'function') callback(); }); -}, 50); +}; /** * Clear undo and redo history stacks @@ -191,6 +198,7 @@ fabric.Canvas.prototype.clearUndo = function () { // 如果在做一些操作之后,需要撤销上一步的操作并刷新历史记录(想在监听modified事件后做些额外的操作并记录操作后的历史),可以调用这个方法 fabric.Canvas.prototype.refreshHistory = function () { + this.historyProcessing = false; this.historyStack.splice(--this.historyIndex); this._historySaveAction(); }; From 01f99e984ce027191513ea3f92d5b579750f16e0 Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Mon, 14 Oct 2024 17:27:19 +0800 Subject: [PATCH 06/11] refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin --- packages/core/utils/fabric-history.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/core/utils/fabric-history.js b/packages/core/utils/fabric-history.js index 1c9ba590..af744779 100644 --- a/packages/core/utils/fabric-history.js +++ b/packages/core/utils/fabric-history.js @@ -2,14 +2,13 @@ * @Author: 秦少卫 * @Date: 2024-07-09 13:46:14 * @LastEditors: George GeorgeSmith163@163.com - * @LastEditTime: 2024-10-14 11:33:33 + * @LastEditTime: 2024-10-14 16:16:16 * @Description: file content */ /** * Override the initialize function for the _historyInit(); */ import { fabric } from 'fabric'; -import { debounce } from 'lodash-es'; fabric.Canvas.prototype.initialize = (function (originalFn) { return function (...args) { @@ -69,6 +68,8 @@ fabric.Canvas.prototype._historyInit = function () { this.historyNextState = this._historyNext(); // 需要两次操作的标记,为true时表示当前操作记录为最新记录,需要撤销两步,因为最顶层的是当前的最新记录,undo一次后后置为false this.isLatestHistoryState = true; + // 正在读取历史记录的标记,为 true 时不允许 undo/redo + this.isLoadingHistory = false; this.on(this._historyEvents()); }; @@ -109,6 +110,7 @@ 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 @@ -133,6 +135,7 @@ 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 @@ -151,8 +154,10 @@ fabric.Canvas.prototype.redo = function (callback) { } }; -// loadFromJSON 是异步操作,所以加了防抖,不然当页面复杂且快速 undo/redo 多次后,可能会在之前的历史上 redo/undo -fabric.Canvas.prototype._loadHistory = debounce(function (history, event, callback) { +// loadFromJSON 是异步操作,所以通过 isLoadingHistory = true 表示历史读取中,不可 undo/redo, +// 不然当页面复杂且快速 undo/redo 多次后,可能会在之前的历史上 redo/undo +fabric.Canvas.prototype._loadHistory = function (history, event, callback) { + this.isLoadingHistory = true; var that = this; // 需要把历史记录中的 workspace 的 evented 属性设置为 false,否则会导致历史记录恢复后,鼠标悬浮 workspace 出现可操作的样式 @@ -163,10 +168,11 @@ fabric.Canvas.prototype._loadHistory = debounce(function (history, event, callba that.renderAll(); that.fire(event); that.historyProcessing = false; + that.isLoadingHistory = false; if (callback && typeof callback === 'function') callback(); }); -}, 50); +}; /** * Clear undo and redo history stacks @@ -191,6 +197,7 @@ fabric.Canvas.prototype.clearUndo = function () { // 如果在做一些操作之后,需要撤销上一步的操作并刷新历史记录(想在监听modified事件后做些额外的操作并记录操作后的历史),可以调用这个方法 fabric.Canvas.prototype.refreshHistory = function () { + this.historyProcessing = false; this.historyStack.splice(--this.historyIndex); this._historySaveAction(); }; From b305e3c30cd4cbdbeb6a936c9cf8d8375bb3e004 Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Tue, 15 Oct 2024 09:26:05 +0800 Subject: [PATCH 07/11] refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin --- packages/core/utils/fabric-history.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/utils/fabric-history.js b/packages/core/utils/fabric-history.js index af744779..c98e3e00 100644 --- a/packages/core/utils/fabric-history.js +++ b/packages/core/utils/fabric-history.js @@ -118,7 +118,7 @@ fabric.Canvas.prototype.undo = function (callback) { this.historyProcessing = true; // 当前操作记录为最新记录,需要撤销两步,因为最顶层的是当前的最新记录 - this.isLatestHistoryState && --this.historyIndex && (this.isLatestHistoryState = false); + this.isLatestHistoryState && this.historyIndex-- && (this.isLatestHistoryState = false); const history = this.historyStack[--this.historyIndex]; if (history) { // Push the current state to the redo history From 53f792bf88690a1b6636b6c86a858a7c2aba831f Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Tue, 15 Oct 2024 09:38:11 +0800 Subject: [PATCH 08/11] refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin --- packages/core/plugin/HistoryPlugin.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/core/plugin/HistoryPlugin.ts b/packages/core/plugin/HistoryPlugin.ts index b6c7eccf..c0683126 100644 --- a/packages/core/plugin/HistoryPlugin.ts +++ b/packages/core/plugin/HistoryPlugin.ts @@ -3,7 +3,7 @@ * @Author: 秦少卫 * @Date: 2023-06-20 13:06:31 * @LastEditors: George GeorgeSmith163@163.com - * @LastEditTime: 2024-10-11 11:11:11 + * @LastEditTime: 2024-10-15 09:35:35 * @Description: 历史记录插件 */ import { fabric } from 'fabric'; @@ -18,12 +18,11 @@ declare module '@kuaitu/core' { } type callback = () => void; -type IEditor = Editor; type extendCanvas = { undo: (callback?: callback) => void; redo: (callback?: callback) => void; clearHistory: () => void; - historyStack: any[]; + historyStack: () => void; historyIndex: number; }; From 2342f92ccd62afe5706ff79770bcd7933c996db1 Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Tue, 15 Oct 2024 09:41:14 +0800 Subject: [PATCH 09/11] refactor(fabric-history): refactor the fabric-history and tuning the HistoryPlugin --- packages/core/plugin/HistoryPlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/plugin/HistoryPlugin.ts b/packages/core/plugin/HistoryPlugin.ts index c0683126..0c6acf65 100644 --- a/packages/core/plugin/HistoryPlugin.ts +++ b/packages/core/plugin/HistoryPlugin.ts @@ -22,7 +22,7 @@ type extendCanvas = { undo: (callback?: callback) => void; redo: (callback?: callback) => void; clearHistory: () => void; - historyStack: () => void; + historyStack: any[]; historyIndex: number; }; From 1ef4398f814b2f228f86a8ecbf817763d8d6f01a Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Tue, 29 Oct 2024 14:06:51 +0800 Subject: [PATCH 10/11] feat(plugin): adding support for the middle mouse button event to drag the workspace --- packages/core/plugin/DringPlugin.ts | 3 +- packages/core/plugin/MiddleMousePlugin.ts | 49 +++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 packages/core/plugin/MiddleMousePlugin.ts diff --git a/packages/core/plugin/DringPlugin.ts b/packages/core/plugin/DringPlugin.ts index 573bc701..78e8c177 100644 --- a/packages/core/plugin/DringPlugin.ts +++ b/packages/core/plugin/DringPlugin.ts @@ -49,7 +49,8 @@ export class DringPlugin implements IPluginTempl { const This = this; this.canvas.on('mouse:down', function (this: ExtCanvas, opt) { const evt = opt.e; - if (evt.altKey || This.dragMode) { + // evt.button === 1 为鼠标中键的判断 + if (evt.altKey || This.dragMode || evt.button === 1) { This.canvas.setCursor('grabbing'); This.canvas.discardActiveObject(); This._setDring(); diff --git a/packages/core/plugin/MiddleMousePlugin.ts b/packages/core/plugin/MiddleMousePlugin.ts new file mode 100644 index 00000000..67b8a155 --- /dev/null +++ b/packages/core/plugin/MiddleMousePlugin.ts @@ -0,0 +1,49 @@ +/* + * @Author: George + * @Date: 2024-10-29 11:11:11 + * @LastEditors: George + * @LastEditTime: 2024-10-29 11:11:11 + * @Description: 鼠标中键点击事件插件 + */ + +import { fabric } from 'fabric'; +import type { IEditor, IPluginTempl } from '@kuaitu/core'; + +class MiddleMousePlugin implements IPluginTempl { + static pluginName = 'MiddleMousePlugin'; + workspaceEl!: HTMLElement; + + constructor(public canvas: fabric.Canvas, public editor: IEditor) { + this.init(); + } + + private init() { + const workspaceEl = document.querySelector('#workspace') as HTMLElement; + if (!workspaceEl) { + throw new Error('element #workspace is missing, plz check!'); + } + this.workspaceEl = workspaceEl; + this.initListener(); + } + + private handleMouseUp = (e: MouseEvent) => e.button === 1 && this.canvas.fire('mouse:up', { e }); + + private handleMouseDown = (e: MouseEvent) => + e.button === 1 && this.canvas.fire('mouse:down', { e }); + + /** + * @desc 初始化鼠标中键监听事件 + */ + private initListener() { + this.workspaceEl.addEventListener('mouseup', this.handleMouseUp); + this.workspaceEl.addEventListener('mousedown', this.handleMouseDown); + } + + destroy() { + this.workspaceEl.removeEventListener('mouseup', this.handleMouseUp); + this.workspaceEl.removeEventListener('mousedown', this.handleMouseDown); + console.log('pluginDestroy'); + } +} + +export default MiddleMousePlugin; From d6b2fb9a912a6ea360cfb61f44d04288296be63d Mon Sep 17 00:00:00 2001 From: GeorgeSmith Date: Tue, 29 Oct 2024 14:52:07 +0800 Subject: [PATCH 11/11] feat(plugin): adding support for the middle mouse button event to drag the workspace --- packages/core/index.ts | 1 + src/views/home/index.vue | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/core/index.ts b/packages/core/index.ts index c0ef129c..16132fae 100644 --- a/packages/core/index.ts +++ b/packages/core/index.ts @@ -39,6 +39,7 @@ export { default as ImageStroke } from './plugin/ImageStroke'; export { default as ResizePlugin } from './plugin/ResizePlugin'; export { default as LockPlugin } from './plugin/LockPlugin'; export { default as AddBaseTypePlugin } from './plugin/AddBaseTypePlugin'; +export { default as MiddleMousePlugin } from './plugin/MiddleMousePlugin'; import EventType from './eventType'; import Utils from './utils/utils'; import CustomRect from './objects/CustomRect'; diff --git a/src/views/home/index.vue b/src/views/home/index.vue index b53039c2..12cd1539 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -274,6 +274,7 @@ import Editor, { LockPlugin, AddBaseTypePlugin, MaskPlugin, + MiddleMousePlugin, } from '@kuaitu/core'; import Edit from '@/components/edit.vue'; import ClipImage from '@/components/clipImage.vue'; @@ -392,6 +393,7 @@ onMounted(() => { .use(ResizePlugin) .use(LockPlugin) .use(AddBaseTypePlugin) + .use(MiddleMousePlugin) .use(MaskPlugin); state.show = true;