0.0.27 • Published 7 years ago

jsplumb-react v0.0.27

Weekly downloads
69
License
GPL-3.0
Repository
gitlab
Last release
7 years ago

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

NameLinksSource
Vanillacodedemo

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 = (
    xOffset: number,
    yOffset: number
  ) => {
    this.setState({xOffset, yOffset});
  }

  private handleZoom = (
    scale: number
  ) => {
    this.setState({scale});
  }

  private handleDrop = (
    id: string,
    x: number,
    y: number
  ) => {
    this.setState({nodes: {
      ...this.state.nodes,
      [id]: {...this.state.nodes[id], x, y}
    }});
  }

  private handleAddConnection = (
    source: string,
    id: string,
    target: string
  ) => {
    this.setState({connections: [
      ...this.state.connections,
      {id, source, target}
    ]});
  }

  private handleRemoveConnection = (
    id: string,
    source: string
  ) => {
    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)TypeDefaultDescription
bridge(connectionId: string, sourceId?: string, targetId?: string, onRemoveConnection?: onRemoveConnection ) => ReactElement | false<Close />A render prop to generate a component over connections
classNamestring'container'Class name applied to react-pan-and-zoom-hoc.
connectionsGraphConnection[][]An array of jsPlumb connection objects. See below for connection object properties.
heightReactText (string | number)500Height of container.
* idstringThe html id used by the jsPlumb instance. Must be unique across the page
maxScalenumber2The maximum scale (zoom) factor
minScalenumber0.5The minimum scale (zoom) factor
onAddConnection(connectionId: string, sourceId: string, targetId: string) => anyInvoked 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.
passOnPropsbooleanfalse(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.
renderOnChangebooleanfalse(from react-pan-and-zoom-hoc) if true, when panning or zooming, it will force a re-render of the component.
scalenumber1Scale (zoom) of the graph
scaleFactornumberMath.sqrt(1.5)The increment/decrement scale (zoom) factor
settingsobjectProvided default settingsA jsPlumb default settings object
styleCSSProperties{position: 'relative', userSelect: 'none'}Style applied to react-pan-and-zoom-hoc component
styleNamestring'container'Class name applied to react-pan-and-zoom-hoc. (For react-css-modules users)
widthReactText (string | number)500Width of container.
xOffsetnumber0.0x-coordinate that represents the left position of the graph
yOffsetnumber0.0y-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)TypeDefaultDescription
allowLoopbackbooleanfalseSet whether this node allows loopback connections
children(id?: string, drag?: boolean) => (ReactElement) | null() => ()A render prop to generate node content component.
classNamestring'jsplumb-react-node'Class name applied to root div
dragSettingsobject{filter: ':not(.jsplumb-react-node)'}katavorio drag settings. Note: drag and stop callback settings are overridden and call invoke props onDrag and onDrop respectively.
* idstringThe 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
sourceSettingsobject{filter: ':not(.jsplumb-react-node)'}jsPlumb continuous anchor makeSource settings.
styleCSSProperties{left: 0, position: 'absolute', top: 0, whiteSpace: 'nowrap'}Style applied to root div
styleNamestring'node'Class name applied to root div. (For react-css-modules users)
targetSettingsobject{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)TypeDescription
bridge(connectionId: string, sourceId?: string, targetId?: string, onRemoveConnection?: onRemoveConnection ) => ReactElement | falseA render prop to generate a component over connections. Overrides default provided in Graph
* idstringThe connection id.
* sourcestringThe connection source id.
* targetstringThe connection target id.

Outstanding Issues

IssueDescription
Touch screen selection
Time travel
Mediocre performance
0.0.27

7 years ago

0.0.26

7 years ago

0.0.23

7 years ago

0.0.22

7 years ago

0.0.21

7 years ago

0.0.20

7 years ago

0.0.19

7 years ago

0.0.18

7 years ago

0.0.17

7 years ago

0.0.16

7 years ago

0.0.15

7 years ago

0.0.14

7 years ago

0.0.13

7 years ago

0.0.12

7 years ago

0.0.11

7 years ago

0.0.10

7 years ago

0.0.9

7 years ago

0.0.8

7 years ago

0.0.7

7 years ago

0.0.6

7 years ago

0.0.5

7 years ago

0.0.4

7 years ago

0.0.3

8 years ago

0.0.2

8 years ago