Browse Source

feat: paste blocks in the mouse position

Ahmad Kholid 3 years ago
parent
commit
7ff466ac95
1 changed files with 60 additions and 18 deletions
  1. 60 18
      src/components/newtab/workflow/WorkflowBuilder.vue

+ 60 - 18
src/components/newtab/workflow/WorkflowBuilder.vue

@@ -42,6 +42,7 @@
       v-model="contextMenu.show"
       :options="contextMenu.position"
       padding="p-3"
+      @close="clearContextMenu"
     >
       <ui-list class="space-y-1 w-52">
         <ui-list-item
@@ -220,6 +221,20 @@ export default {
         active: nodeContent,
       });
     }
+    function getRelativePosToEditor(clientX, clientY) {
+      const { x, y } = editor.value.precanvas.getBoundingClientRect();
+      const { clientWidth, clientHeight } = editor.value.precanvas;
+      const { zoom } = editor.value;
+
+      const xPosition =
+        clientX * (clientWidth / (clientWidth * zoom)) -
+        x * (clientWidth / (clientWidth * zoom));
+      const yPosition =
+        clientY * (clientHeight / (clientHeight * zoom)) -
+        y * (clientHeight / (clientHeight * zoom));
+
+      return { xPosition, yPosition };
+    }
     function dropHandler({ dataTransfer, clientX, clientY, target }) {
       const block = JSON.parse(dataTransfer.getData('block') || null);
 
@@ -302,20 +317,7 @@ export default {
 
       if (block.fromBlockBasic) return;
 
-      const xPosition =
-        clientX *
-          (editor.value.precanvas.clientWidth /
-            (editor.value.precanvas.clientWidth * editor.value.zoom)) -
-        editor.value.precanvas.getBoundingClientRect().x *
-          (editor.value.precanvas.clientWidth /
-            (editor.value.precanvas.clientWidth * editor.value.zoom));
-      const yPosition =
-        clientY *
-          (editor.value.precanvas.clientHeight /
-            (editor.value.precanvas.clientHeight * editor.value.zoom)) -
-        editor.value.precanvas.getBoundingClientRect().y *
-          (editor.value.precanvas.clientHeight /
-            (editor.value.precanvas.clientHeight * editor.value.zoom));
+      const { xPosition, yPosition } = getRelativePosToEditor(clientX, clientY);
 
       const blockId = editor.value.addNode(
         block.id,
@@ -418,7 +420,9 @@ export default {
       activeNode = null;
     }
     function duplicateBlock(nodeId, isPaste = false) {
+      let initialPos = null;
       const nodes = new Map();
+
       const addNode = (id) => {
         const node = editor.value.getNodeFromId(id);
 
@@ -431,6 +435,15 @@ export default {
         store.state.copiedNodes.forEach((node) => {
           nodes.set(node.id, node);
         });
+
+        const pos = contextMenu?.position?.getReferenceClientRect?.() ?? null;
+        if (pos) {
+          const { xPosition, yPosition } = getRelativePosToEditor(
+            pos.left,
+            pos.top
+          );
+          initialPos = { x: xPosition, y: yPosition };
+        }
       } else {
         if (nodeId) addNode(nodeId);
         else if (activeNode) addNode(activeNode.id);
@@ -442,10 +455,12 @@ export default {
         });
       }
 
-      const nodesOutputs = [];
-
       clearSelectedElements();
 
+      const nodesOutputs = [];
+      let firstNodePos = null;
+      let index = 0;
+
       nodes.forEach((node) => {
         const { outputs, inputs } = tasks[node.name];
 
@@ -455,12 +470,28 @@ export default {
         const blockInputs = inputsLen || inputs;
         const blockOutputs = outputsLen || outputs;
 
+        let nodePosX = node.pos_x;
+        let nodePosY = node.pos_y;
+
+        if (initialPos && index === 0) {
+          firstNodePos = { x: nodePosX, y: nodePosY };
+
+          nodePosX = initialPos.x;
+          nodePosY = initialPos.y;
+        } else if (firstNodePos) {
+          const xDistance = nodePosX - firstNodePos.x;
+          const yDistance = nodePosY - firstNodePos.y;
+
+          nodePosX = initialPos.x + xDistance;
+          nodePosY = initialPos.y + yDistance;
+        }
+
         const newNodeId = editor.value.addNode(
           node.name,
           blockInputs,
           blockOutputs,
-          node.pos_x + 25,
-          node.pos_y + 70,
+          nodePosX + 25,
+          nodePosY + 70,
           node.name,
           node.data,
           node.html,
@@ -483,6 +514,8 @@ export default {
         if (outputsLen > 0) {
           nodesOutputs.push({ id: newNodeId, outputs: node.outputs });
         }
+
+        index += 1;
       });
 
       if (nodesOutputs.length < 1) return;
@@ -640,6 +673,14 @@ export default {
         selectedElements.push(nodeProperties);
       }
     }
+    function clearContextMenu() {
+      Object.assign(contextMenu, {
+        items: [],
+        data: null,
+        show: false,
+        position: {},
+      });
+    }
     function copyBlocks() {
       let nodes = selectedElements;
 
@@ -897,6 +938,7 @@ export default {
       contextMenu,
       dropHandler,
       handleDragOver,
+      clearContextMenu,
       contextMenuHandler: {
         copyBlocks,
         deleteBlock,