diff --git a/packages/editor-ui/src/components/CanvasControls.vue b/packages/editor-ui/src/components/CanvasControls.vue new file mode 100644 index 0000000000000..d2afb4eed2aaf --- /dev/null +++ b/packages/editor-ui/src/components/CanvasControls.vue @@ -0,0 +1,81 @@ + + + + diff --git a/packages/editor-ui/src/components/mixins/moveNodeWorkflow.ts b/packages/editor-ui/src/components/mixins/moveNodeWorkflow.ts index 0884215d94049..cae47b0116c4f 100644 --- a/packages/editor-ui/src/components/mixins/moveNodeWorkflow.ts +++ b/packages/editor-ui/src/components/mixins/moveNodeWorkflow.ts @@ -1,6 +1,4 @@ import mixins from 'vue-typed-mixins'; -// @ts-ignore -import normalizeWheel from 'normalize-wheel'; import { deviceSupportHelpers } from '@/components/mixins/deviceSupportHelpers'; import { getMousePosition } from '@/views/canvasHelpers'; import { mapStores } from 'pinia'; @@ -88,12 +86,5 @@ export const moveNodeWorkflow = mixins( this.moveWorkflow(e); }, - wheelMoveWorkflow (e: WheelEvent) { - const normalized = normalizeWheel(e); - const offsetPosition = this.uiStore.nodeViewOffsetPosition; - const nodeViewOffsetPositionX = offsetPosition[0] - (e.shiftKey ? normalized.pixelY : normalized.pixelX); - const nodeViewOffsetPositionY = offsetPosition[1] - (e.shiftKey ? normalized.pixelX : normalized.pixelY); - this.uiStore.nodeViewOffsetPosition = [nodeViewOffsetPositionX, nodeViewOffsetPositionY]; - }, }, }); diff --git a/packages/editor-ui/src/declarations/normalize-wheel.d.ts b/packages/editor-ui/src/declarations/normalize-wheel.d.ts new file mode 100644 index 0000000000000..a78742bf17e71 --- /dev/null +++ b/packages/editor-ui/src/declarations/normalize-wheel.d.ts @@ -0,0 +1,9 @@ +declare module 'normalize-wheel' { + function normalizeWheel(e: WheelEvent): { spinX : number, + spinY : number, + pixelX : number, + pixelY : number + }; + + export = normalizeWheel; +} diff --git a/packages/editor-ui/src/stores/canvas.ts b/packages/editor-ui/src/stores/canvas.ts new file mode 100644 index 0000000000000..0153719755c5c --- /dev/null +++ b/packages/editor-ui/src/stores/canvas.ts @@ -0,0 +1,129 @@ +import { computed, ref } from 'vue'; +import { defineStore } from 'pinia'; +import { jsPlumb } from 'jsplumb'; +import { v4 as uuid } from 'uuid'; +import normalizeWheel from 'normalize-wheel'; +import { useWorkflowsStore } from '@/stores/workflows'; +import { useNodeTypesStore } from '@/stores/nodeTypes'; +import { useUIStore } from '@/stores/ui'; +import { INodeUi, XYPosition } from '@/Interface'; +import * as CanvasHelpers from '@/views/canvasHelpers'; +import { START_NODE_TYPE } from '@/constants'; +import '@/plugins/N8nCustomConnectorType'; +import '@/plugins/PlusEndpointType'; + +export const useCanvasStore = defineStore('canvas', () => { + const workflowStore = useWorkflowsStore(); + const nodeTypesStore = useNodeTypesStore(); + const uiStore = useUIStore(); + const jsPlumbInstance = jsPlumb.getInstance(); + + const nodes = computed(() => workflowStore.allNodes); + const triggerNodes = computed( + () => nodes.value.filter( + node => node.type === START_NODE_TYPE || nodeTypesStore.isTriggerNode(node.type), + ), + ); + const isDemo = ref(false); + const nodeViewScale = ref(1); + const canvasAddButtonPosition = ref([1, 1]); + + const setRecenteredCanvasAddButtonPosition = (offset?: XYPosition) => { + const position = CanvasHelpers.getMidCanvasPosition(nodeViewScale.value, offset || [0, 0]); + + position[0] -= CanvasHelpers.PLACEHOLDER_TRIGGER_NODE_SIZE / 2; + position[1] -= CanvasHelpers.PLACEHOLDER_TRIGGER_NODE_SIZE / 2; + + canvasAddButtonPosition.value = CanvasHelpers.getNewNodePosition(nodes.value, position); + }; + + const getPlaceholderTriggerNodeUI = (): INodeUi => { + setRecenteredCanvasAddButtonPosition(); + + return { + id: uuid(), + ...CanvasHelpers.DEFAULT_PLACEHOLDER_TRIGGER_BUTTON, + position: canvasAddButtonPosition.value, + }; + }; + + const getNodesWithPlaceholderNode = (): INodeUi[] => + triggerNodes.value.length > 0 ? nodes.value : [getPlaceholderTriggerNodeUI(), ...nodes.value]; + + const setZoomLevel = (zoomLevel: number, offset: XYPosition) => { + nodeViewScale.value = zoomLevel; + jsPlumbInstance.setZoom(zoomLevel); + uiStore.nodeViewOffsetPosition = offset; + }; + + const resetZoom = () => { + const {scale, offset} = CanvasHelpers.scaleReset({ + scale: nodeViewScale.value, + offset: uiStore.nodeViewOffsetPosition, + }); + setZoomLevel(scale, offset); + }; + + const zoomIn = () => { + const {scale, offset} = CanvasHelpers.scaleBigger({ + scale: nodeViewScale.value, + offset: uiStore.nodeViewOffsetPosition, + }); + setZoomLevel(scale, offset); + }; + + const zoomOut = () => { + const {scale, offset} = CanvasHelpers.scaleSmaller({ + scale: nodeViewScale.value, + offset: uiStore.nodeViewOffsetPosition, + }); + setZoomLevel(scale, offset); + }; + + const zoomToFit = () => { + const nodes = getNodesWithPlaceholderNode(); + if (!nodes.length) { // some unknown workflow executions + return; + } + const {zoomLevel, offset} = CanvasHelpers.getZoomToFit(nodes, !isDemo.value); + setZoomLevel(zoomLevel, offset); + }; + + const wheelMoveWorkflow = (e: WheelEvent) => { + const normalized = normalizeWheel(e); + const offsetPosition = uiStore.nodeViewOffsetPosition; + const nodeViewOffsetPositionX = offsetPosition[0] - (e.shiftKey ? normalized.pixelY : normalized.pixelX); + const nodeViewOffsetPositionY = offsetPosition[1] - (e.shiftKey ? normalized.pixelX : normalized.pixelY); + uiStore.nodeViewOffsetPosition = [nodeViewOffsetPositionX, nodeViewOffsetPositionY]; + }; + + const wheelScroll = (e: WheelEvent) => { + //* Control + scroll zoom + if (e.ctrlKey) { + if (e.deltaY > 0) { + zoomOut(); + } else { + zoomIn(); + } + + e.preventDefault(); + return; + } + wheelMoveWorkflow(e); + }; + + return { + jsPlumbInstance, + isDemo, + nodeViewScale, + canvasAddButtonPosition, + setRecenteredCanvasAddButtonPosition, + getNodesWithPlaceholderNode, + setZoomLevel, + resetZoom, + zoomIn, + zoomOut, + zoomToFit, + wheelScroll, + }; +}); diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index d8d73aba10ae6..2599589bd5264 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -15,7 +15,7 @@ @mousedown="mouseDown" v-touch:tap="touchTap" @mouseup="mouseUp" - @wheel="wheelScroll" + @wheel="canvasStore.wheelScroll" >
-
- - - - -
+
@@ -137,11 +127,11 @@