Skip to content

Commit

Permalink
refactor: 重构历史记录插件 (#311)
Browse files Browse the repository at this point in the history
* refactor: 重构历史记录插件

* feat: 完善历史记录插件
  • Loading branch information
ddshiyu authored Mar 14, 2024
1 parent cfb4cff commit b8c0a34
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 60 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"color-gradient-picker-vue3": "^2.0.7",
"events": "^3.3.0",
"fabric": "^5.2.1",
"fabric-history": "^1.6.0",
"fontfaceobserver": "^2.1.0",
"hotkeys-js": "^3.8.8",
"lodash-es": "^4.17.21",
Expand Down Expand Up @@ -68,4 +69,4 @@
"prettier --write"
]
}
}
}
26 changes: 16 additions & 10 deletions src/components/history.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,29 @@
<template>
<div style="display: inline-block">
<!-- 后退 -->
<Tooltip :content="$t('history.revocation') + `(${undoStack.length})`">
<Button @click="undo" type="text" size="small" :disabled="undoStack.length === 0">
<Tooltip :content="$t('history.revocation') + `(${canUndo})`">
<Button @click="undo" type="text" size="small" :disabled="!canUndo">
<Icon type="ios-undo" size="20" />
</Button>
</Tooltip>

<!-- 重做 -->
<Tooltip :content="$t('history.redo') + `(${redoStack.length})`">
<Button @click="redo" type="text" size="small" :disabled="redoStack.length === 0">
<Tooltip :content="$t('history.redo') + `(${canRedo})`">
<Button @click="redo" type="text" size="small" :disabled="!canRedo">
<Icon type="ios-redo" size="20" />
</Button>
</Tooltip>

<span class="time" v-if="history.length">
<!-- <span class="time" v-if="history.length">
{{ useDateFormat(history[0].timestamp, 'HH:mm:ss').value }}
</span>
</span> -->
</div>
</template>

<script setup lang="ts">
import { useDateFormat } from '@vueuse/core';
import useSelect from '@/hooks/select';
const { canvasEditor } = useSelect() as { canvasEditor: any };
const { history, redoStack, undoStack } = reactive(canvasEditor.getHistory());
const canUndo = ref(0);
const canRedo = ref(0);
// 后退
const undo = () => {
canvasEditor.undo();
Expand All @@ -42,6 +40,13 @@ const undo = () => {
const redo = () => {
canvasEditor.redo();
};
onMounted(() => {
canvasEditor.on('historyUpdate', (canUndoParam: number, canRedoParam: number) => {
canUndo.value = canUndoParam;
canRedo.value = canRedoParam;
});
});
</script>

<style scoped lang="less">
Expand All @@ -50,6 +55,7 @@ span.active {
fill: #2d8cf0;
}
}
.time {
color: #c1c1c1;
}
Expand Down
79 changes: 30 additions & 49 deletions src/core/plugin/HistoryPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,86 +6,67 @@
* @LastEditTime: 2024-02-20 13:33:29
* @Description: 历史记录插件
*/

import { fabric } from 'fabric';
import Editor from '../core';
import { ref } from 'vue';
import { useRefHistory } from '@vueuse/core';
import 'fabric-history';

type IEditor = Editor;
type extendCanvas = {
undo: () => void;
redo: () => void;
clearHistory: () => void;
historyUndo: any[];
historyRedo: any[];
};

class HistoryPlugin {
public canvas: fabric.Canvas;
public canvas: fabric.Canvas & extendCanvas;
public editor: IEditor;
static pluginName = 'HistoryPlugin';
static apis = ['undo', 'redo', 'getHistory'];
static events = ['historyInitSuccess'];
static apis = ['undo', 'redo'];
static events = ['historyUpdate'];
public hotkeys: string[] = ['ctrl+z', 'ctrl+shift+z', '⌘+z', '⌘+shift+z'];
history: any;
constructor(canvas: fabric.Canvas, editor: IEditor) {
constructor(canvas: fabric.Canvas & extendCanvas, editor: IEditor) {
this.canvas = canvas;
this.editor = editor;

this._init();
}

_init() {
this.history = useRefHistory(ref(), {
capacity: 50,
this.canvas.getObjects().forEach((item) => {
this.canvas.add(item);
});
this.canvas.on({
'object:added': (event: fabric.IEvent) => this._save(event),
'object:modified': (event: fabric.IEvent) => this._save(event),
'selection:updated': (event: fabric.IEvent) => this._save(event),
this.canvas.on('history:append', () => {
this.historyUpdate();
});
window.addEventListener('beforeunload', function (e) {
if (history.length > 0) {
window.addEventListener('beforeunload', (e) => {
if (this.canvas.historyUndo.length > 0) {
(e || window.event).returnValue = '确认离开';
}
});
}

// 导入模板之后,清理 History 缓存
hookImportAfter() {
this.history.clear();
historyUpdate() {
const { historyUndo, historyRedo } = this.canvas;
this.editor.emit('historyUpdate', historyUndo.length, historyRedo.length);
}

getHistory() {
return this.history;
}
_save(event: fabric.IEvent) {
// 过滤选择元素事件
const isSelect = event.action === undefined && event.e;
if (isSelect || !this.canvas) return;
const workspace = this.canvas.getObjects().find((item) => item.id === 'workspace');
if (!workspace) {
return;
}
if (this.history.isTracking.value) {
this.history.source.value = this.editor.getJson();
}
// 导入模板之后,清理 History 缓存
hookImportAfter() {
this.canvas.clearHistory();
this.historyUpdate();
}

undo() {
if (this.history.canUndo.value) {
this.history.undo();
this.renderCanvas();
}
this.canvas.undo();
this.historyUpdate();
}

redo() {
this.history.redo();
this.renderCanvas();
this.canvas.redo();
this.historyUpdate();
}

renderCanvas = () => {
this.history.pause();
this.canvas.clear();
this.canvas.loadFromJSON(this.history.source.value, () => {
this.canvas.renderAll();
this.history.resume();
});
};

// 快捷键扩展回调
hotkeyEvent(eventName: string, e: any) {
if (e.type === 'keydown') {
Expand Down

0 comments on commit b8c0a34

Please sign in to comment.