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:
- A container for the Drawflow canvas.
- 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 adata-node
attribute to identify the node type. - Canvas (
#drawflow
): The main canvas where nodes will be dropped.
Step 2: Enable Drag-and-Drop Functionality
Drawflow has built-in support for drag-and-drop. To enable it, we need to:
- Attach
draggable
attributes to the sidebar items. - 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: