Drawflow: Drag-and-Drop Flowchart Builder in JavaScript

Category: Chart & Graph , Javascript | September 3, 2024
Authorjerosoler
Last UpdateSeptember 3, 2024
LicenseMIT
Views37,713 views
Drawflow: Drag-and-Drop Flowchart Builder in JavaScript

Drawflow is a dependency-free JavaScript library for building editable node-based SVG flowcharts and data-flow editors in the browser.

You work on a canvas-style editor where you can drag nodes, connect inputs and outputs, and edit data stored inside each node.

Drawflow runs in plain JavaScript and stores the complete flow as JSON for import and export. Registered nodes can also render Vue 2 or Vue 3 components.

Features:

  • Drag-and-drop nodes with multiple inputs and outputs.
  • Multiple connections between nodes.
  • Node and connection deletion.
  • Dynamic input and output management.
  • Reroute points for connection lines.
  • Node data synchronization through df-* attributes.
  • Zoom controls and canvas translation.
  • Edit, fixed, and view modes.
  • Multiple flow modules.
  • JSON import and export.
  • Mouse, touch, keyboard, and pinch-zoom controls.
  • Vue 2, Vue 3, and Nuxt integration.

Install & Download:

NPM

Install Drawflow from npm and import both the JavaScript module and stylesheet.

npm install drawflow
import Drawflow from 'drawflow';
import 'drawflow/dist/drawflow.min.css';

Browser CDN

You can also load the stylesheet and global JavaScript build from a CDN.

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/drawflow.min.css" />
<script src="https://unpkg.com/[email protected]/dist/drawflow.min.js"></script>

How to use it:

1. Create the editor container

Create an empty DIV container with a fixed height.

<div id="drawflow"></div>
<style>
#drawflow {
  position: relative;
  width: 100%;
  height: 500px;
}
</style>

2. Initialize Drawflow

Create the editor instance from the container, then call start().

const canvas = document.getElementById('drawflow');
const editor = new Drawflow(canvas);
editor.start();

3. Add nodes

addNode() accepts the node name, input and output counts, canvas position, CSS class, data object, HTML content, and optional node type. Add df-* attributes to inputs, textareas, selects, or contenteditable elements when their values should sync with node data. Nested keys can use multiple levels such as df-user-name.

const nodeData = {
  title: 'Profile'
};
const nodeHtml = `
  <div>
    <label>Title</label>
    <input type="text" df-title placeholder="Node title">
  </div>
`;
editor.addNode(
  'profile',
  0,
  1,
  120,
  160,
  'profile-node',
  nodeData,
  nodeHtml,
  false
);

4. Register reusable nodes

Register a DOM element once when the same node markup appears in multiple places.

const taskNode = document.createElement('div');
taskNode.innerHTML = '<strong>Task</strong>';
editor.registerNode('taskCard', taskNode);
editor.addNode('task', 1, 1, 320, 180, 'task-node', {}, 'taskCard', true);

5. Export and import flow data

Use JSON-compatible data to save the current flow and restore it later.

const savedFlow = editor.export();
editor.import(savedFlow);

6. Work with modules

Modules store multiple flows inside one editor instance. The default module is Home.

editor.addModule('Review');
editor.changeModule('Review');
editor.removeModule('Review');
editor.changeModule('Home');

7. Change editor modes

edit is the default mode. fixed locks node positions while keeping node fields available. view provides a read-only view.

editor.editor_mode = 'edit';
editor.editor_mode = 'fixed';
editor.editor_mode = 'view';

Mouse, Touch & Keyboard Controls:

  • Press Delete to remove the selected node or connection.
  • Right-click a selected item to show its remove control.
  • Long-press on mobile for the remove action.
  • Drag with the left mouse button to move nodes or the editor canvas.
  • Hold Ctrl while using the mouse wheel to zoom.
  • Use pinch gestures to zoom on touch devices.

Editor Options:

Set reroute before start() or import() when reroute points should appear during initial rendering. Other editor properties can be assigned directly on the instance.

  • reroute (Boolean, default false) activates reroute points on connections.
  • reroute_fix_curvature (Boolean, default false) applies fixed curvature around reroute points.
  • curvature (Number, default 0.5) sets connection curvature.
  • reroute_curvature_start_end (Number, default 0.5) sets curvature for the first and last reroute segments.
  • reroute_curvature (Number, default 0.5) sets curvature between reroute points.
  • reroute_width (Number, default 6) sets the reroute point width.
  • line_path (Number, default 5) sets the connection line width.
  • force_first_input (Boolean, default false) sends a dropped connection to the first input on the node.
  • editor_mode (String, default edit) accepts edit, fixed, or view.
  • zoom (Number, default 1) sets the current zoom level.
  • zoom_max (Number, default 1.6) sets the maximum zoom level.
  • zoom_min (Number, default 0.5) sets the minimum zoom level.
  • zoom_value (Number, default 0.1) sets the zoom increment.
  • zoom_last_value (Number, default 1) stores the previous zoom level.
  • draggable_inputs (Boolean, default true) lets input controls start node dragging.
  • useuuid (Boolean, default false) assigns UUIDs to newly created node IDs.
editor.reroute = true;
editor.zoom_min = 0.5;
editor.zoom_max = 1.6;
editor.zoom_value = 0.1;
editor.useuuid = true;
editor.start();

API Methods:

Editor, Nodes & Data

// Start rendering and attach editor interactions.
editor.start();
// Register reusable DOM or Vue node content. props and options apply to Vue nodes.
editor.registerNode(name, html, props, options);
// Add a node and return its new node ID.
const nodeId = editor.addNode(name, inputs, outputs, posx, posy, className, data, html, typeNode);
// Get node data by its raw ID, such as 5.
editor.getNodeFromId(5);
// Get an array of IDs for nodes with the same name.
editor.getNodesFromName('profile');
// Remove a node. This method expects the DOM-style ID.
editor.removeNodeId('node-5');
// Replace the data object stored by a node.
editor.updateNodeDataFromId(5, { title: 'Updated' });
// Add or remove node inputs and outputs.
editor.addNodeInput(5);
editor.addNodeOutput(5);
editor.removeNodeInput(5, 'input_2');
editor.removeNodeOutput(5, 'output_2');

Connections

// Create a connection between two nodes.
editor.addConnection(5, 8, 'output_1', 'input_1');
// Remove one connection. Returns true when a matching connection exists.
editor.removeSingleConnection(5, 8, 'output_1', 'input_1');
// Recalculate the rendered connection positions for a node.
editor.updateConnectionNodes('node-5');
// Remove every connection attached to a node.
editor.removeConnectionNodeId('node-5');

Modules

// Return the module that contains a node.
editor.getModuleFromNodeId(5);
// Create, open, or remove a module.
editor.addModule('Review');
editor.changeModule('Review');
editor.removeModule('Review');
// Clear the active module.
editor.clearModuleSelected();
// Clear all flow data and recreate an empty Home data object.
editor.clear();

Zoom

// Increase, decrease, or reset the editor zoom.
editor.zoom_in();
editor.zoom_out();
editor.zoom_reset();

Import & Export

// Export the complete Drawflow data object.
const savedFlow = editor.export();
// Replace the current editor data and render the imported flow.
editor.import(savedFlow);

Events:

editor.on('nodeCreated', function(id) {
  console.log(id);
});
editor.on('nodeRemoved', function(id) {
  console.log(id);
});
editor.on('nodeDataChanged', function(id) {
  console.log(id);
});
editor.on('nodeSelected', function(id) {
  console.log(id);
});
editor.on('nodeUnselected', function(value) {
  console.log(value);
});
editor.on('nodeMoved', function(id) {
  console.log(id);
});
editor.on('connectionStart', function(connection) {
  console.log(connection.output_id, connection.output_class);
});
editor.on('connectionCancel', function(value) {
  console.log(value);
});
editor.on('connectionCreated', function(connection) {
  console.log(connection.output_id, connection.input_id, connection.output_class, connection.input_class);
});
editor.on('connectionRemoved', function(connection) {
  console.log(connection.output_id, connection.input_id, connection.output_class, connection.input_class);
});
editor.on('connectionSelected', function(connection) {
  console.log(connection);
});
editor.on('connectionUnselected', function(value) {
  console.log(value);
});
editor.on('addReroute', function(id) {
  console.log(id);
});
editor.on('removeReroute', function(id) {
  console.log(id);
});
editor.on('rerouteMoved', function(id) {
  console.log(id);
});
editor.on('moduleCreated', function(name) {
  console.log(name);
});
editor.on('moduleChanged', function(name) {
  console.log(name);
});
editor.on('moduleRemoved', function(name) {
  console.log(name);
});
editor.on('click', function(event) {
  console.log(event);
});
editor.on('clickEnd', function(event) {
  console.log(event);
});
editor.on('contextmenu', function(event) {
  console.log(event);
});
editor.on('mouseMove', function(position) {
  console.log(position.x, position.y);
});
editor.on('mouseUp', function(event) {
  console.log(event);
});
editor.on('keydown', function(event) {
  console.log(event);
});
editor.on('zoom', function(zoom_level) {
  console.log(zoom_level);
});
editor.on('translate', function(position) {
  console.log(position.x, position.y);
});
editor.on('import', function(value) {
  console.log(value);
});
function handleExport(data) {
  console.log(data);
}
editor.on('export', handleExport);
editor.removeListener('export', handleExport);

Alternatives & Related Resources:

Changelog:

v0.0.60 (09/03/2024)

  • Bugfix

v0.0.59 (06/30/2022)

  • Bugfix

v0.0.58 (05/04/2022)

  • [Bug] Right click when creating a connection
  • [Breaking] Input inside nodes are not editable

v0.0.57 (05/03/2022)

  • Fix issue where Safari attempts to select text during drag operations

v0.0.56 (04/28/2022)

  • Fix chrome zoom
  • Fix reroute points add and remove

v0.0.55 (01/04/2022)

  • Fix remove listeners

v0.0.54 (11/29/2021)

  • Multiples classname nodes

v0.0.53 (11/11/2021)

  • Fix Path disapear on chrome zoom

v0.0.52 (10/27/2021)

  • Add new event mouseUp

v0.0.51 (10/20/2021)

  • Fix Vue 3 AddNodeImport

v0.0.50 (10/20/2021)

  • Add support for Vue 3

v0.0.48 (08/05/2021)

  • Fix css zoom

v0.0.47 (08/05/2021)

  • Fix Misaligned routes when chrome zoom is not 100%
  • Removed unused css

v0.0.46 (08/05/2021)

  • Add event nodeDataChanged

v0.0.45 (07/10/2021)

  • Add event rerouteMoved
  • Fix event importon change module
  • Removed old code and comments

v0.0.44 (07/08/2021)

  • Fixed the parent instance for Vue

v0.0.43 (07/03/2021)

  • Fix container query dom.

v0.0.42 (05/15/2021)

  • Fix df-attributes updates

v0.0.41 (05/14/2021)

  • Fix df- attribute levels

v0.0.40 (04/05/2021)

  • Added ‘view’ editor mode

v0.0.39 (03/19/2021)

  • Bugfix

v0.0.38 (02/27/2021)

  • Fix: data node null value

v0.0.37 (02/20/2021)

  • Use of UUID as node id instead if integer index. Swithable between index and UUID use.

v0.0.35 (02/14/2021)

  • add: connectionStart & connectionCancel event

v0.0.34 (01/28/2021)

  • add: connectionSelected and connectionUnselected events

v0.0.33 (01/12/2021)

  • fix: Drag type select

v0.0.32 (12/08/2020)

  • add: Support vue3

v0.0.31 (11/29/2020)

  • add: updateNodeDataFromId function

v0.0.30 (11/11/2020)

  • fix:zoom on translate canvas
  • add:zoom_last_value

v0.0.29 (11/08/2020)

  • fix: force_first_input with 0 inputs

v0.0.27 (10/25/2020)

  • Added clickEnd event

v0.0.26 (10/16/2020)

  • Fix removeNodeOutput and removeNodeInput more than 10 items

v0.0.25 (09/22/2020)

  • Added context menu event

v0.0.24 (09/16/2020)

  • Fix nodemoved fire event (only on move)

v0.0.23 (08/28/2020)

  • Removed console log

v0.0.20 (08/25/2020)

  • Fix addConnection reroute

v0.0.20 (08/07/2020)

  • Added reroute fix curvatures

v0.0.19 (08/06/2020)

  • Added reroute fix curvatures

v0.0.18 (08/02/2020)

  • Fix reroute connections back connections

v0.0.17 (08/01/2020)

  • Fix removeNodeOutput with reroutes points

v0.0.15 (07/30/2020)

  • added removeNodeInput And removeNodeOutput

v0.0.14 (07/28/2020)

  • added addNodeOutput and addNodeInput function

v0.0.13 (07/24/2020)

  • Add removeSingleConnection

v0.0.11 (07/15/2020)

  • Fix Remove connection before node removed

v0.0.10 (07/12/2020)

  • Added addConnection API.

v0.0.9 (07/12/2020)

  • Update

07/06/2020

  • Added ‘import’ event

You Might Be Interested In:


Leave a Reply