jsplumb-react
TypeScript icon, indicating that this package has built-in type declarations

0.0.27 • Public • Published

jsPlumb React

Commitizen Friendly Semantic Release
Build Status Coverage Report Build Analysis NPM Version License FOSSA Status Canonical Code Style


jsplumb-react is a minimal reactive wrapper to jsPlumb. Uses react-pan-and-zoom-hoc for pan and zoom capabilities.

Warning: this project is still alpha quality with possible breaking changes with each release. Contributions welcome.

Installation

npm install jsplumb jsplumb-react

Demo

Name Links Source
Vanilla code demo

Simple example

/* typescript */
 
import {Connections} from 'index';
import debounce from 'lodash.debounce';
import React, {
  CSSProperties,
  PureComponent
} from 'react';
import {AutoSizer} from 'react-virtualized';
import {
  Graph,
  Node,
  NodeContent
} from 'jsplumb-react';
import './Diagram.css';
 
const style: CSSProperties = {
  height: 50
};
 
const nodes: {
  [key: string]: {
    label: string,
    style: CSSProperties
  }
} = {
  node1: {
    label: 'node 1',
    style: {
      left: 272.5,
      top: 233
    }
  },
  node2: {
    label: 'node 2',
    style: {
      left: 672.5,
      top: 233
    }
  }
};
 
const connections: Connections = [
  {
    id: 'connection1',
    source: 'node1',
    target: 'node2'
  },
];
 
export interface IDiagramState {
  connections: Connections;
  height: number;
  maxScale?: number;
  minScale?: number;
  nodes: IDiagramNodes;
  scale: number;
  width: number;
  xOffset: number;
  yOffset: number;
}
 
export default class Diagram extends PureComponent<{}, IDiagramState> {
  public state = {
    connections,
    height: 500,
    maxScale: 2,
    minScale: 0.25,
    nodes: nodes as IDiagramNodes,
    scale: 1,
    width: 500,
    xOffset: 0.0,
    yOffset: 0.0
  };
 
  private handleResize = debounce(
    ({height, width}: {height: number, width: number}) => {
      this.setState({height, width});
    },
    400,
    {trailing: true}
  );
 
  public render () {
    const children = Object.keys(this.state.nodes).map((id) => {
      const {label, type} = this.state.nodes[id];
 
      return (
        <Node
          id={id}
          key={id}
          onDrop={this.handleDrop}
          style={this.state.nodes[id].style}
          styleName='node'
        >
          {this.children}
        </Node>
      );
    });
 
    return (
      <div styleName='canvas'>
        <AutoSizer onResize={this.handleResize}>
          {() => null}
        </AutoSizer>
        <Graph
          connections={this.state.connections}
          height={this.state.height}
          id={'simpleDiagram'}
          maxScale={this.state.maxScale}
          minScale={this.state.minScale}
          onAddConnection={this.handleAddConnection}
          onRemoveConnection={this.handleRemoveConnection}
          onPanEnd={this.handlePanEnd}
          onZoom={this.handleZoom}
          scale={this.state.scale}
          width={this.state.width}
          xOffset={this.state.xOffset}
          yOffset={this.state.yOffset}
        >
          {children}
        </Graph>
      </div>
    );
  }
 
  private children = (id: string, drag: boolean) => (
    <NodeContent
      id={id}
      label={this.state.nodes[id].label}
      onRemoveNode={this.handleClose}
      style={style}
    >
      {this.state.nodes[id].label || id}
    </NodeContent>
  )
 
  private handleClose = (nodeId: string) => {
    if (confirm('Remove node \'' + nodeId + '\'?')) {
      const {[nodeId]: omit, ...remaining} = this.state.nodes;
      this.setState({
        connections: this.state.connections.filter(connection => (
          connection.source !== nodeId && connection.target !== nodeId
        )),
        nodes: remaining
      });
    }
  }
 
  private handlePanEnd = (
    xOffsetnumber,
    yOffsetnumber
  ) => {
    this.setState({xOffset, yOffset});
  }
 
  private handleZoom = (
    scalenumber
  ) => {
    this.setState({scale});
  }
 
  private handleDrop = (
    idstring,
    xnumber,
    ynumber
  ) => {
    this.setState({nodes: {
      ...this.state.nodes,
      [id]: {...this.state.nodes[id], x, y}
    }});
  }
 
  private handleAddConnection = (
    sourcestring,
    idstring,
    targetstring
  ) => {
    this.setState({connections: [
      ...this.state.connections,
      {id, source, target}
    ]});
  }
 
  private handleRemoveConnection = (
    idstring,
    sourcestring
  ) => {
    if (confirm('Remove connection \'' + id + '\'?')) {
      this.setState({connections: this.state.connections.filter(connection => (
        connection.id !== id
      ))});
    }
  }
}
 

API

graph Definition Properties

The graph is the initializer and container component of the jsplumb instance.

Name (*required) Type Default Description
bridge (connectionId: string, sourceId?: string, targetId?: string, onRemoveConnection?: onRemoveConnection ) => ReactElement | false <Close /> A render prop to generate a component over connections
className string 'container' Class name applied to react-pan-and-zoom-hoc.
connections GraphConnection[] [] An array of jsPlumb connection objects. See below for connection object properties.
height ReactText (string | number) 500 Height of container.
* id string The html id used by the jsPlumb instance. Must be unique across the page
maxScale number 2 The maximum scale (zoom) factor
minScale number 0.5 The minimum scale (zoom) factor
onAddConnection (connectionId: string, sourceId: string, targetId: string) => any Invoked when an additional connection is created.
onPanAndZoom (x?: number, y?: number, scale?: number, event?: MouseEvent) => any (from react-pan-and-zoom-hoc) Invoked when the component pans and zooms (for example when the mouse wheel is used).
onPanEnd (x?: number, y?: number, event?: MouseEvent) => any; (from react-pan-and-zoom-hoc) Invoked when the component stop panning.
onPanMove (x?: number, y?: number, event?: MouseEvent) => any; (from react-pan-and-zoom-hoc) Invoked when the component pans in the x or y direction.
onPanStart (event?: MouseEvent) => any; (from react-pan-and-zoom-hoc) Invoked when the component starts to pan.
onRemoveConnection (connectionId: string, sourceId: string) => any; Invoked when a connection is removed via node removal.
onSelect (selected: id[]) => any; Invoked when a node is selected.
onZoom (x?: number, y?: number, scale?: number, event?: MouseEvent) => any; (from react-pan-and-zoom-hoc) currently not used, reserved for future use.
passOnProps boolean false (from react-pan-and-zoom-hoc) if true, will pass on the x, y, and scale props to the wrapped component. If renderOnChange is also set to true this will cause the props (with updated values) to be passed on every time a pan or zoom event occurs.
renderOnChange boolean false (from react-pan-and-zoom-hoc) if true, when panning or zooming, it will force a re-render of the component.
scale number 1 Scale (zoom) of the graph
scaleFactor number Math.sqrt(1.5) The increment/decrement scale (zoom) factor
settings object Provided default settings A jsPlumb default settings object
style CSSProperties {position: 'relative', userSelect: 'none'} Style applied to react-pan-and-zoom-hoc component
styleName string 'container' Class name applied to react-pan-and-zoom-hoc. (For react-css-modules users)
width ReactText (string | number) 500 Width of container.
xOffset number 0.0 x-coordinate that represents the left position of the graph
yOffset number 0.0 y-coordinate that represents the top position of the graph

node Definition Properties

node component is a wrapper content for each node. It provides defaults drag, anchor, and connection behaviours.

Name (*required) Type Default Description
allowLoopback boolean false Set whether this node allows loopback connections
children (id?: string, drag?: boolean) => (ReactElement) | null () => (
)
A render prop to generate node content component.
className string 'jsplumb-react-node' Class name applied to root div
dragSettings object {filter: ':not(.jsplumb-react-node)'} katavorio drag settings. Note: drag and stop callback settings are overridden and call invoke props onDrag and onDrop respectively.
* id string The node html id. jsplumb and katavorio bind to this id. Must be unique across the page
onDrag (id: string, x: number, y: number) => any; Invoked while node is dragged.
onDrop (id: string, x: number, y: number) => any; Invoked after node is released from drag.
onSelect (selected: string[]) => any; Invoked when a node is selected. Overrides onSelect provided in Graph
sourceSettings object {filter: ':not(.jsplumb-react-node)'} jsPlumb continuous anchor makeSource settings.
style CSSProperties {left: 0, position: 'absolute', top: 0, whiteSpace: 'nowrap'} Style applied to root div
styleName string 'node' Class name applied to root div. (For react-css-modules users)
targetSettings object {allowLoopback: true, dragOptions: {hoverClass: 'dragHover'}} jsPlumb continuous anchor makeTarget settings.
type 'both' | false | 'source' | 'target' 'both' Set node to accept connections, generate connections, or both. Set to false if not using continuous anchors

connection object properties

node component is a wrapper content for each node.

Name (*required) Type Description
bridge (connectionId: string, sourceId?: string, targetId?: string, onRemoveConnection?: onRemoveConnection ) => ReactElement | false A render prop to generate a component over connections. Overrides default provided in Graph
* id string The connection id.
* source string The connection source id.
* target string The connection target id.

Outstanding Issues

Issue Description
Touch screen selection
Time travel
Mediocre performance

Package Sidebar

Install

npm i jsplumb-react

Weekly Downloads

21

Version

0.0.27

License

GPL-3.0

Unpacked Size

158 kB

Total Files

9

Last publish

Collaborators

  • wallzerobot