Drawflow Tutorial: 3. Add Nodes Through Drag and Drop

In the last tutorial, we covered how to programmatically add and connect nodes using editor.import(). Now, let’s make things more interactive by enabling users to drag and drop nodes into the canvas. This feature is perfect for creating a dynamic interface where users can customize workflows.

Here’s how you can implement drag-and-drop functionality to add nodes.


Step 1: Set Up a Basic HTML Structure

To start, we need:

  1. A container for the Drawflow canvas.
  2. A list of options that users can drag into the canvas.

Here’s a simple HTML structure:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Drawflow Drag and Drop</title>
  <link rel="stylesheet" href="https://unpkg.com/drawflow@0.0.60/dist/drawflow.min.css">
  <script src="https://unpkg.com/drawflow@0.0.60/dist/drawflow.min.js"></script>
  <style>
    * {
        margin: 0;
        padding: 0;
    }
    .page-container {
        display: flex;
        height: 100vh;
    }
    .drag-items {
        display: flex;
        flex-direction: column;
        gap: 10px;
        width: 300px;
        padding: 20px;
        border-right: 2px solid #ddd;
    }
    .drag-item {
        background-color: rgb(159 18 57);
        color: #fee;
        padding: 10px 20px;
        border-radius: 4px;
        font-size: 1.2rem;
    }
    .drawflow-column {
        flex: 1;
        border: 2px solid #ddd;
        margin: 40px;
        border-radius: 10px;
    }
    .drawflow {
        height: 100%;
    }
  </style>
</head>
<body>

<div class="page-container">
  <!-- Sidebar with draggable options -->
  <div class="drag-items">
    <div class="drag-item" draggable="true" data-node="node1">Node 1</div>
    <div class="drag-item" draggable="true" data-node="node2">Node 2</div>
  </div>

  <div class="drawflow-column">
    <!-- Drawflow Canvas -->
    <div id="drawflow" class="drawflow"></div>
  </div>
</div>

<script>
  const drawflowContainer = document.getElementById('drawflow');
  const editor = new Drawflow(drawflowContainer);
  editor.start();
</script>

</body>
</html>

Explanation

  • Sidebar (.drag-items): Contains two draggable items, each with a data-node attribute to identify the node type.
  • Canvas (#drawflow): The main canvas where nodes will be dropped.

Drawflow drag and drop screenshot initial


Step 2: Enable Drag-and-Drop Functionality

Drawflow has built-in support for drag-and-drop. To enable it, we need to:

  1. Attach draggable attributes to the sidebar items.
  2. Set up event listeners for drag-and-drop actions.

Here’s how to wire up the logic:

// Enable drag from the sidebar
const dragItems = document.querySelectorAll('.drag-item');

dragItems.forEach(item => {
  item.addEventListener('dragstart', event => {
    event.dataTransfer.setData('node', event.target.getAttribute('data-node'));
  });
});

  // Enable drop on the canvas
  drawflowContainer.addEventListener('drop', event => {
    event.preventDefault();
    const nodeName = event.dataTransfer.getData('node');

    const { x, y } = editor.precanvas.getBoundingClientRect();
    const posX = event.clientX - x;
    const posY = event.clientY - y;

    addNewNode(nodeName, posX, posY);

  });

  // Select the node equivalent to the item that has been dropped over the canvas
  function addNewNode(name, pos_x, pos_y) {
    switch (name) {
        case 'node1':
            const node1 = `<div>Node 1 Content with output</div>`
            editor.addNode('Node 1', 0,  1, pos_x, pos_y, '', {}, node1 );
            break;
        case 'node2':
            const node2 = `<div>Node 2 Content with input</div>`
            editor.addNode('Node 2', 1,  0, pos_x, pos_y, '', {}, node2 );
            break;
        case 'node3':
            const node3 = `<div>Node 3 Content with input and output</div>`
            editor.addNode('Node 3', 1,  1, pos_x, pos_y, '', {}, node3 );
            break;
    }

  }

// Prevent default behavior for dragover
drawflowContainer.addEventListener('dragover', event => {
  event.preventDefault();
});

Step 3: Test the Drag-and-Drop

Here’s the complete setup:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Drawflow Drag and Drop</title>
  <link rel="stylesheet" href="https://unpkg.com/drawflow@0.0.60/dist/drawflow.min.css">
  <script src="https://unpkg.com/drawflow@0.0.60/dist/drawflow.min.js"></script>
  <style>
    * {
        margin: 0;
        padding: 0;
    }

    .page-container {
        display: flex;
        height: 100vh;
    }
    .drag-items {
        display: flex;
        flex-direction: column;
        gap: 10px;
        width: 300px;
        padding: 20px;
        border-right: 2px solid #ddd;
    }
    .drag-item {
        background-color: rgb(159 18 57);
        color: #fee;
        padding: 10px 20px;
        border-radius: 4px;
        font-size: 1.2rem;
    }
    .drawflow-column {
        flex: 1;
        border: 2px solid #ddd;
        margin: 40px;
        border-radius: 10px;
    }
    .drawflow {
        height: 100%;
    }
  </style>

</head>
<body>

<div class="page-container">
  <!-- Sidebar with draggable options -->
  <div class="drag-items">
    <div class="drag-item" draggable="true" data-node="node1">Node 1</div>
    <div class="drag-item" draggable="true" data-node="node2">Node 2</div>
    <div class="drag-item" draggable="true" data-node="node3">Node 3</div>
  </div>

  <div class="drawflow-column">
    <!-- Drawflow Canvas -->
    <div id="drawflow" class="drawflow"></div>
  </div>
</div>

<script>
  const drawflowContainer = document.getElementById('drawflow');
  const editor = new Drawflow(drawflowContainer);
  editor.start();

  // Enable drag from the sidebar
  const dragItems = document.querySelectorAll('.drag-item');

  dragItems.forEach(item => {
    item.addEventListener('dragstart', event => {
      event.dataTransfer.setData('node', event.target.getAttribute('data-node'));
    });
  });

  // Enable drop on the canvas
  drawflowContainer.addEventListener('drop', event => {
    event.preventDefault();
    const nodeName = event.dataTransfer.getData('node');

    const { x, y } = editor.precanvas.getBoundingClientRect();
    const posX = event.clientX - x;
    const posY = event.clientY - y;

    addNewNode(nodeName, posX, posY);

  });


  function addNewNode(name, pos_x, pos_y) {
    switch (name) {
        case 'node1':
            const node1 = `<div>Node 1 Content with output</div>`
            editor.addNode('Node 1', 0,  1, pos_x, pos_y, '', {}, node1 );
            break;
        case 'node2':
            const node2 = `<div>Node 2 Content with input</div>`
            editor.addNode('Node 2', 1,  0, pos_x, pos_y, '', {}, node2 );
            break;
        case 'node3':
            const node3 = `<div>Node 3 Content with input and output</div>`
            editor.addNode('Node 3', 1,  1, pos_x, pos_y, '', {}, node3 );
            break;
    }

  }


  // Prevent default behavior for dragover
  drawflowContainer.addEventListener('dragover', event => {
    event.preventDefault();
  });
</script>

</body>
</html>

You should get the following end result:

Drawflow drag and drop screenshot final

author's bio photo

Hi there! I am Avic Ndugu.

I have published 100+ blog posts on HTML, CSS, Javascript, React and other related topics. When I am not writing, I enjoy reading, hiking and listening to podcasts.