npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dataflow-diagram

v0.1.0

Published

React-based DFD / flowchart diagram editor with SVG canvas, draggable shapes, port routing, and an adjustable orthogonal connector with ghost-handle segment editing.

Readme

dataflow-diagram

A React-based DFD / flowchart diagram editor for the browser. Built on a custom SVG renderer with draggable shapes, port-aware connectors, and an adjustable orthogonal connector featuring ghost-handle segment editing (like Syncfusion's orthogonal connector).

  • 25+ built-in flowchart shapes (rectangle, diamond, document, database, predefined process, manual input, off-page connectors, summing junction, etc.)
  • Multiple connector types: straight, orthogonal (sharp + rounded), wave, polyangled, and a fully adjustable orthogonal connector with mid-segment drag handles
  • Auto-routing path that re-stitches when endpoints move; trims itself when the head/tail is dropped back onto the line
  • Zoom-aware canvas that grows automatically when shapes are dragged past the visible edge
  • Undo/redo, selection, context menu, copy/paste primitives in the engine
  • TypeScript types shipped

Installation

npm install dataflow-diagram
# or
pnpm add dataflow-diagram
# or
yarn add dataflow-diagram

Peer dependencies (React 18 or 19):

npm install react react-dom

Quick start

import { useEffect, useMemo, useState } from 'react';
import { DataflowEngine, DataflowCanvas } from 'dataflow-diagram';
import 'dataflow-diagram/styles.css'; // shape/arrow icons + canvas styles

export default function App() {
  const [version, setVersion] = useState(0);

  const engine = useMemo(
    () =>
      new DataflowEngine({
        onDiagramChanged: () => setVersion(v => v + 1),
      }),
    []
  );

  // Seed a couple of nodes
  useEffect(() => {
    engine.createNode('rectangle', {
      id: 'a', label: 'Start',
      x: 80, y: 80, width: 120, height: 60,
      ports: ['a-top', 'a-right', 'a-bottom', 'a-left'],
    });
    engine.createNode('diamond', {
      id: 'b', label: 'Decision',
      x: 320, y: 80, width: 120, height: 80,
      ports: ['b-top', 'b-right', 'b-bottom', 'b-left'],
    });
    setVersion(v => v + 1);
  }, [engine]);

  return (
    <div style={{ width: '100%', height: '600px', position: 'relative' }}>
      <DataflowCanvas
        engine={engine}
        width={800}
        height={600}
        version={version}
        editMode
        zoom={1}
      />
    </div>
  );
}

User manual

The canvas

<DataflowCanvas> renders an SVG inside a scrollable host. The host:

  • Scrolls with browser-native scrollbars when content overflows.
  • Grows beyond width/height props automatically when a node or edge is positioned past the visible edge (with 80 px padding).
  • Scales content via CSS transform: scale(zoom); the host dimensions are pre-multiplied so scrollbars appear in lockstep.

Place the canvas inside a parent with explicit dimensions (e.g. height: 600px). The component fills 100% of that parent.

Selecting and editing

  • Click a shape or line → selects it. Resize handles appear for nodes.
  • Right-click a shape or line → opens a context menu (Delete / Duplicate).
  • Click empty canvas → clears selection.
  • Delete / Backspace → removes the selected node or edge.
  • Set editMode={false} to render in read-only mode (no drag handles or context menus).

Adding shapes

Either drive it imperatively from your own toolbar, or use the bundled <Toolbox>:

import { Toolbox } from 'dataflow-diagram';

<Toolbox
  onAddShape={(type) => engine.createNode(type, { x: 100, y: 100, width: 120, height: 60, ports: [] })}
  onAddEdge={(type) => engine.createEdge?.(type, /* ... */)}
/>

Built-in shape types: rectangle, circle, diamond, oval, document, inputOutput, predefinedProcess, internalStorage, loopLimit, manualInput, multipleDocuments, storedData, manualLoop, directData, display, database, delay, offPageConnector, preparation, offPageConnectorRight, collate, merge, or, summingJunction, sort.

Connector types

| edge.type | Description | | --- | --- | | straight | Plain straight line with arrowhead. | | OrthogonalRight | Right-then-down L. | | OrthogonalDown | Down-then-right L. | | OrthogonalRightRound / OrthogonalDownRound | Same L's with rounded corner. | | RightwardsWave | Sine wave going right. | | polyangled | Single V bend. | | PloigonalArrow | Multi-segment polygonal arrow. | | adjustable-connector | Auto-routed orthogonal connector with draggable ghost handles at every segment midpoint. Drag a horizontal segment vertically (or a vertical segment horizontally) to bend the path. When you drop the source/target endpoint back onto the connector's own line, the connector auto-trims the redundant waypoints. |

Editing an adjustable connector

  1. Click the connector to select it. Small blue squares appear at the midpoint of every segment.
  2. Drag a midpoint:
    • On a horizontal segment → drag up/down to move the segment vertically.
    • On a vertical segment → drag left/right to move it horizontally.
  3. To retract the line, grab the source or target endpoint dot and drop it on a segment of the same connector — the bypassed waypoints are dropped.

Zoom

<DataflowCanvas> accepts a zoom prop (default 2). Wire it up to your own zoom UI:

const [zoom, setZoom] = useState(1);
<DataflowCanvas engine={engine} zoom={zoom} ... />
<button onClick={() => setZoom(z => z + 0.1)}>+</button>

The scroller and SVG hit-area scale together — drag works correctly at any zoom.


API reference

DataflowEngine

Headless state container. All graph mutations go through it.

const engine = new DataflowEngine({
  snapToGrid?: boolean,
  gridSize?: number,
  onNodeSelected?: (id: string) => void,
  onEdgeSelected?: (id: string) => void,
  onConnectionCreated?: (edge: Edge) => void,
  onDiagramChanged?: (graph: DiagramGraph) => void,
  onClickedOutside?: (e: Event) => void,
});

| Method | Purpose | | --- | --- | | setEditMode(mode) | Toggle read-only mode. | | getGraph() | Returns the current DiagramGraph. | | createNode(type, config) | Add a node. | | updateNode(id, updates) | Mutate a node (e.g. on drag). | | selectNode(id) / selectEdge(id) | Programmatic selection. | | deleteNode(id) / deleteEdge(id) | Remove. | | copyNode(id) / copyEdge(id) | Duplicate with an offset. | | updateEdge(id, updates) | Mutate an edge (used by drag handlers). | | clearSelection(e) | Deselect all. | | undo() / redo() | Time-travel through the debounced history. |

<DataflowCanvas>

| Prop | Type | Default | Notes | | --- | --- | --- | --- | | engine | DataflowEngine | — | Required. | | width / height | number | — | Minimum logical canvas dimensions (in SVG units). | | version | number | — | Bump after engine mutations to force re-render. Wire up onDiagramChanged to setVersion(v => v + 1). | | editMode | boolean | false | Toggle drag handles + context menus. | | zoom | number | 2 | CSS scale of the SVG; host grows in lockstep. | | onNodeSelected | (id: string) => void | — | Called when a node is clicked. | | onEdgeSelected | (id: string) => void | — | Called when an edge is clicked. |

Type exports

import type {
  DiagramGraph,
  NodeConfig,
  EdgeConfig,
  Edge,
  AdjustableEdge,
  Point,
  PortConfig,
  LabelProps,
  ArrowHeadType,
} from 'dataflow-diagram';

Adjustable connector helpers

For programmatic path manipulation outside the canvas:

import {
  createAdjustableConnector,
  autoRouteOrthogonal,
  buildOrthogonalPoints,
  getAdjustableConnectorPath,
  trimOnSelfHit,
} from 'dataflow-diagram';
  • buildOrthogonalPoints(source, target, userPoints[]) — returns the full point list including source/target with auto-inserted bridge corners.
  • autoRouteOrthogonal(s, t) — Z-shape between two points, picks the bend axis based on which delta dominates.
  • getAdjustableConnectorPath(edge) — returns an SVG M…L… path string.
  • trimOnSelfHit(source, target, userPoints, which) — if the moved endpoint lands on the connector's own line, returns the trimmed waypoints (null otherwise).

Custom shapes and edges

Register your own renderer:

import { registerShape, registerEdge } from 'dataflow-diagram';

registerShape('myShape', (node, svgNS) => {
  const el = document.createElementNS(svgNS, 'rect');
  el.setAttribute('x', String(node.x));
  el.setAttribute('y', String(node.y));
  el.setAttribute('width', String(node.width));
  el.setAttribute('height', String(node.height));
  el.setAttribute('fill', node.color || '#ccc');
  el.setAttribute('data-id', node.id);
  return el;
});

registerEdge('myEdge', (edge, svgNS /*, obstacles */) => {
  const line = document.createElementNS(svgNS, 'line');
  // ...build your edge here
  return line;
});

Renderers receive the namespace string ("http://www.w3.org/2000/svg") and must return an SVGElement carrying data-id={node.id} (or the edge id) so drag handlers can hook into it.


Building from source

npm install
npm run build:lib   # produces dist/index.js, dist/index.cjs, dist/index.d.ts, dist/styles.css
npm run dev         # runs the in-repo demo app on http://localhost:5173

The demo lives in src/App.tsx; the publishable library is everything under src/package/.


License

MIT