From 9013e2378977be27835fd5023c7cbdfd02e00aae Mon Sep 17 00:00:00 2001 From: NathanViaud <nathan.viaud@inria.fr> Date: Thu, 6 Apr 2023 15:00:29 +0200 Subject: [PATCH] adding node moved action --- src/features/ePocFlow/ePocFlow.vue | 5 ++ src/shared/interfaces/index.ts | 3 +- src/shared/interfaces/undoRedo.interface.ts | 43 ++++++++++ src/shared/stores/undoRedoStore.ts | 94 +++++++++++++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 src/shared/interfaces/undoRedo.interface.ts create mode 100644 src/shared/stores/undoRedoStore.ts diff --git a/src/features/ePocFlow/ePocFlow.vue b/src/features/ePocFlow/ePocFlow.vue index cd440681..bea8182b 100644 --- a/src/features/ePocFlow/ePocFlow.vue +++ b/src/features/ePocFlow/ePocFlow.vue @@ -15,6 +15,7 @@ const { vueFlowRef, project, updateEdge, edges, nodes, findNode } = useVueFlow( const editorStore = useEditorStore(); const graphStore = useGraphStore(); +const undoRedoStore = useUndoRedoStore(); const nodeTypes = { activity: markRaw(ActivityNode), @@ -173,6 +174,10 @@ function nodeDrag(event) { @edgeclick="onEdgeclick" @pane-click="editorStore.closeFormPanel()" @connect="connect" + @node-drag-start="nodeDragStart" + @node-drag-stop="nodeDragStop" + @keydown.meta.z="undo" + @keydown.meta.y="redo" > <template #node-custom="{ id, data }"> <PageNode :id="id" :data="data" /> diff --git a/src/shared/interfaces/index.ts b/src/shared/interfaces/index.ts index 0ae5d48d..3e9e3cb6 100644 --- a/src/shared/interfaces/index.ts +++ b/src/shared/interfaces/index.ts @@ -5,4 +5,5 @@ export * from './form.interface'; export * from './nodeElement.interface'; export * from './formButton.interface'; export * from './field.interface'; -export * from './pageModel.interface'; \ No newline at end of file +export * from './pageModel.interface'; +export * from './undoRedo.interface'; \ No newline at end of file diff --git a/src/shared/interfaces/undoRedo.interface.ts b/src/shared/interfaces/undoRedo.interface.ts new file mode 100644 index 00000000..b35f079f --- /dev/null +++ b/src/shared/interfaces/undoRedo.interface.ts @@ -0,0 +1,43 @@ +export interface UndoRedoAction { + type: string; +} + +export interface NodeMovedAction extends UndoRedoAction { + type: 'nodeMoved'; + nodeId: string; + deltaMovement: { x: number; y: number }; +} + +//? Is saving an entire node in this situation a good idea? +export interface NodeAddedAction extends UndoRedoAction { + type: 'nodeAdded'; + //TODO: use the type defined by vue flow + node: any; + position: { x: number; y: number }; +} + +export interface NodeRemovedAction extends UndoRedoAction { + type: 'nodeRemoved'; + node: any; + position: { x: number; y: number } +} + +export interface NodeUpdatedAction extends UndoRedoAction { + type: 'nodeUpdated'; + node: any; +} + +export interface EdgeConnectedAction extends UndoRedoAction { + type: 'edgeConnected'; + edge: any; +} + +export interface EdgeUpdatedAction extends UndoRedoAction { + type: 'edgeUpdated'; + edge: any; +} + +export interface EdgeRemovedAction extends UndoRedoAction { + type: 'edgeRemoved'; + edge: any; +} \ No newline at end of file diff --git a/src/shared/stores/undoRedoStore.ts b/src/shared/stores/undoRedoStore.ts new file mode 100644 index 00000000..c364b87e --- /dev/null +++ b/src/shared/stores/undoRedoStore.ts @@ -0,0 +1,94 @@ +import { defineStore } from 'pinia'; +import { UndoRedoAction, NodeMovedAction } from '../interfaces'; +import { useVueFlow } from '@vue-flow/core'; + +const { findNode } = useVueFlow({ id: 'main' }); + +interface UndoRedoState { + undoStack: UndoRedoAction[]; + redoStack: UndoRedoAction[]; +} + +export const useUndoRedoStore = defineStore('epoc', { + state: (): UndoRedoState => ({ + undoStack: [], + redoStack: [], + }), + + actions: { + undo(): void { + if(this.undoStack.length === 0) return; + + const action = this.undoStack.pop(); + this.executeAction(action, this.redoStack); + }, + redo(): void { + if(this.redoStack.length === 0) return; + + const action = this.redoStack.pop(); + this.executeAction(action, this.undoStack); + }, + addAction(action: UndoRedoAction): void { + this.undoStack.push(action); + this.redoStack = []; + }, + executeAction(action: UndoRedoAction, reverseStack: UndoRedoAction[]): void { + switch(action.type) { + case 'nodeMoved': + this.moveNode(action, reverseStack); + break; + case 'nodeRemoved': + this.deleteNode(action); + break; + case 'nodeAdded': + this.addNode(action); + break; + case 'nodeUpdated': + this.updateNode(action); + break; + case 'edgeConnected': + this.connectEdge(action); + break; + case 'edgeUpdated': + this.updateEdge(action); + break; + case 'edgeRemoved': + this.deleteEdge(action); + break; + } + }, + moveNode(action: NodeMovedAction, reverseStack: UndoRedoAction[]): void { + const node = findNode(action.nodeId); + node.position.x -= action.deltaMovement.x; + node.position.y -= action.deltaMovement.y; + + const reverseAction: NodeMovedAction = { + type: 'nodeMoved', + nodeId: action.nodeId, + deltaMovement: { + x: -action.deltaMovement.x, + y: -action.deltaMovement.y + } + }; + reverseStack.push(reverseAction); + }, + deleteNode() { + return; + }, + addNode() { + return; + }, + updateNode() { + return; + }, + connectEdge() { + return; + }, + updateEdge() { + return; + }, + deleteEdge() { + return; + } + } +}); \ No newline at end of file -- GitLab