Integrations / React Integration (Legacy)

React Integration (Legacy)

The jsPlumb Toolkit has several components to assist you to integrate with React. This page provides an overview of the available components in what we are now calling the "legacy" React integration, so named because its the original version of the React integration, and since 2.3.0 there's a new version available which works slightly differently.

For existing users of the Toolkit upgrading to version 2.3.0, you can switch your imports to the imports shown below and there will be no functional difference in your application.

The fundamental difference between the legacy React integration and the current React integration is in the fact that the legacy integration does not render node/group components as children of the Surface component. This has two main ramifications:

  • You cannot pass props down to node/group components
  • Event binding does not work from 17.x onwards

The first of these - passing props to node/group components - is not something that every application needs, but which can be useful: you can change the appearance of your elements without also having to manipulate the underlying Toolkit's data model. The second of these is slightly more fundamental, and is caused by a change React made in 17.x: the element they attach their delegated event listener used to be the document, and now its the root element into which the given React tree was rendered. As node/group components are not rendered in the tree by the legacy integration, event bindings on them do not work in 17.x.

We are not aware of any particular reason that licensees would not want to switch to the current React integration, other than that there may be a few CSS issues, and the methods available on the base component have a couple of different names, but in order to not force anyone to make those changes immediately we've opted to keep the original integration around for 2.3.0. It is deprecated, though, and will be removed in 2.4.0.

For a discussion of what's changed in the current integration, see this page.

The React Legacy integration ships in a separate tar - jsplumbtoolkit-react-legacy.tgz. Add it to your package.json alongside the Toolkit dependency declaration:

 {
    ...
    "dependencies":{
        ...
        "jsplumbtoolkit":"file:path/to/jsplumbtoolkit.tgz",
        "jsplumbtoolkit-react":"file:path/to/jsplumbtoolkit-react-legacy.tgz"
        ...
    }
    ...
}

TOP


The main component you will use is the JsPlumbToolkitSurfaceComponent.

Let's take a quick look at how you'd use one:

class DemoComponent extends React.Component {

    constructor(props) {
        super(props);
        this.toolkit = jsPlumbToolkit.newInstance({
            ...
        });

        this.view = {
            ...
        }

        this.renderParams = {
            ...
        }
    }

    render() {
        return <div style={{width:"100%",height:"100%"}}>
                    <JsPlumbToolkitSurfaceComponent renderParams={this.renderParams} toolkit={this.toolkit} view={this.view} ref={ (c) => { if (c != null) this.surface = c.surface } }/>
                    <ControlsComponent ref={(c) => this.controls = c }/>
                    <DatasetComponent ref={(d) => this.dataset = d }/>
                    <div className="miniview"/>                        
                </div>
    }
        
}

We create an instance of the Toolkit in the component's constructor, which we then inject into the JsPlumbToolkitSurfaceComponent, along with renderParams and the view.

ControlsComponent is something built for the Toolkit React demonstrations, to handle zoom/selection of nodes. DatasetComponent is also part of this demonstration - it's a React version of the dataset view you may have seen on other demonstrations. Neither of these components ships in the React integration package, but you are welcome to grab the code from one of the demonstrations if you wish to use it.

jsPlumb Components

React is component based. The Toolkit offers 3 components:

JsPlumbToolkitSurfaceComponent

<JsPlumbToolkitSurfaceComponent renderParams={this.renderParams} view={this.view} toolkit={this.toolkit}/>
Attributes
  • toolkit A reference to an instance of the Toolkit. Required.
  • renderParams Parameters to pass in to the constructor of the Surface widget. Optional, but you'll probably supply something here.
  • view View parameters. Views are discussed here. Again, optional, but you'll probably want to supply something.

TOP


JsPlumbToolkitMiniviewComponent

Provides a Miniview that can be attached to some Surface component.

Example

import JsPlumbToolkitMiniviewComponent from 'jsplumbtoolkit-react';

const miniview = ReactDOM.render(
    <JsPlumbToolkitMiniviewComponent surface={JsPlumbToolkitSurfaceComponent}/>, document.querySelector(".miniview")
)
Attributes
  • surface The JsPlumbToolkitSurfaceComponent to which to attach the Miniview component.

TOP


SurfaceDropComponent

Provides a means to implement drag/drop of new Nodes/Groups onto your Surface. This component is abstract; you are expected to provide the render method.

Example

First, declare your subclass and provide the render method:


import SurfaceDropComponent from 'jsplumbtoolkit-react';

class MyPalette extends SurfaceDropComponent {

  render() {
    return <div className="someClass">
                <ul>
                    <li data-node-type="foo" jtk-is-group="true">FOO</li>
                    <li data-node-type="bar">BAR</li>
                </ul>
           </div>
  }
}

Then create one in your app:


const typeExtractor = function(el) { return el.getAttribute("data-node-type") };
const dataGenerator = function (type) { return { w:120, h:80 }; };
const nodePaletteElement = document.querySelector(".parentOfNodePalette")

const nodePalette = ReactDOM.render(
        <MyPalette surface={this.surface} selector={"li"} container={nodePaletteElement} dataGenerator={dataGenerator}/>
, nodePaletteElement);

As with the Miniview component, this component needs a reference to a JsPlumbToolkitSurfaceComponent.

Attributes
  • selector:string A valid CSS3 selector identifying descendant nodes that are to be configured as draggable/droppables.
  • dataGenerator:(el:HTMLElement) => T This Function is used to provide default data for some Node/Group. Note that a difference between this component and the original jsplumb-palette is that your dataGenerator function is now expected to determine the "type" of the object being dragged, and to set it on the data object if desired.
  • surface Required. The JsPlumbToolkitSurfaceComponent to which to attach the Drop Manager.
  • allowDropOnGroup:boolean Optional, defaults to true. If true, then elements can be dropped onto nodes/groups, and in the event that occurs, the onDrop method will be called.
  • allowDropOnCanvas:boolean Optional, defaults to true. When an element is dropped on the canvas whitespace, it is added to the dataset and rendered.
  • allowDropOnEdge:boolean Optional, defaults to true. If true, then elements can be dropped onto edges, and in the event that an element is dropped on an edge, a new node/group is added and inserted between the source and target of the original edge, and the original edge is discarded..
  • typeGenerator:(data:T) => string Optional. A function that can return the correct type for some data object representing an element being dragged. By default the Toolkit will use the type member of the data object.
  • groupIdentifier:(d: T, el: HTMLElement) => boolean Optional. By default, the toolkit looks for a jtk-is-group attribute on an element being dragged. If found, with a value of "true", then the Toolkit assumes a group is being dragged. You can supply your own function to make this decision.

For further reading, see this page .

TOP


Each Node or Group in your UI is rendered as an individual component.

Definition

As an example, consider the component we use to render an Action node in the Flowchart builder demonstration:

import React from 'react';
import { BaseEditableComponent } from"./base-component.jsx";

/**
 * Component used to render an action node.
 */
export class ActionComponent extends BaseEditableComponent {

    constructor(props) {
        super(props)
    }

    render() {

        const obj = this.state;

        return <div style={{left:obj.left + 'px', top:obj.top + 'px', width:obj.w + 'px', height:obj.h + 'px'}} className="flowchart-object flowchart-action">
            <div style={{position:'relative'}}>
                <div className="node-edit node-action" onClick={this.edit.bind(this)}>
                    <i className="fa fa-pencil-square-o"/>
                </div>
                <div className="node-delete node-action" onClick={this.remove.bind(this)}>
                    <i className="fa fa-times"/>
                </div>
                <svg width={obj.w} height={obj.h}>
                    <rect x={0} y={0} width={obj.w} height={obj.h} className="outer drag-start"/>
                    <rect x={10} y={10} width={obj.w-20} height={obj.h-20} className="inner"/>
                    <text textAnchor="middle" x={obj.w/2} y={obj.h/2} dominantBaseline="central">{obj.text}</text>
                </svg>
            </div>
            <jtk-target port-type="target"/>
            <jtk-source port-type="source" filter=".outer"/>
        </div>
    }
}

Here, BaseEditableComponent is common for all nodes, and offers a few basic methods like node edit/remove. The class declaration looks like this:


import { BaseNodeComponent }  from 'jsplumbtoolkit-react';
import { Dialogs } from 'jsplumbtoolkit';

export class BaseEditableComponent extends BaseNodeComponent {
    
    ...
}

You must extend BaseNodeComponent in the components you use to render nodes.

Mapping to a type

You map components to node/group types in the view. Here's the nodes section from the view in the React Flowchart Builder application:

this.view = {
    nodes: {
        "start": {
           component:StartComponent
        },
        "selectable": {
            events: {
                tap:  (params) => {
                    this.toolkit.toggleSelection(params.node);
                }
            }
        },
        "question": {
            parent: "selectable",
            component:QuestionComponent
        },
        "action": {
            parent: "selectable",
            component:ActionComponent
        },
        "output":{
            parent:"selectable",
            component:OutputComponent
        }
    },
    // There are two edge types defined - 'yes' and 'no', sharing a common
    // parent.
    edges: {
        ...
    }
}

TOP


JsPlumbToolkitPaletteComponent

Provides a means to implement drag/drop of new Nodes/Groups onto your Surface. This component is abstract; you are expected to provide the render method.

Example

First, declare your subclass and provide the render method:


import JsPlumbToolkitPaletteComponent from 'jsplumbtoolkit-react';

class MyPalette extends JsPlumbToolkitPaletteComponent {

  render() {
    return <div className="someClass">
                <ul>
                    <li data-node-type="foo">FOO</li>
                    <li data-node-type="bar">BAR</li>
                </ul>
           </div>
  }
}

Then create one in your app:


const typeExtractor = function(el) { return el.getAttribute("data-node-type") };
const dataGenerator = function (type) { return { w:120, h:80 }; };
const nodePaletteElement = document.querySelector(".parentOfNodePalette")

const nodePalette = ReactDOM.render(
        <MyPalette surface={this.surface} selector={"li"} typeExtractor={typeExtractor} 
            container={nodePaletteElement} dataGenerator={dataGenerator}/>
, nodePaletteElement);

As with the Miniview component, this component needs a reference to a JsPlumbToolkitSurfaceComponent.

Attributes
  • selector A valid CSS3 selector identifying descendant nodes that are to be configured as draggable/droppables.
  • typeExtractor A Function that, given some DOM element, can return the type of the Node/Group the element represents. In this example, our typeExtractor function would return the value of the data-node-type attribute. Optional.
  • dataGenerator Not shown in our example, this optional Function can be used to provide default data for some Node/Group type. Optional.
  • surface The JsPlumbToolkitSurfaceComponent to which to attach the Palette component.

For further reading on the concept of Palettes, see this page .

TOP