Skip to main content

jsPlumb

Introduction#

jsPlumb Community edition provides a means for a developer to visually connect elements on their web pages, using SVG. jsPlumb works with all modern browsers, both mobile and desktop, and IE11. Versions of Internet Explorer prior to 11 are not supported.

jsPlumb has no external dependencies.

These docs refer to version 5.x of the Community edition of jsPlumb. For version 6.x docs, click here.

Installation#

npm install @jsplumb/browser-ui

jsPlumb ships as several packages:

  • @jsplumb/core The core functionality. Manages connections and endpoints and offers methods to connect elements and add endpoints etc. This package is renderer agnostic and does not depend on the DOM.
  • @jsplumb/browser-ui The default (and currently only) renderer. Equivalent to the jsPlumb class from previous versions. Connects HTML/SVG elements using a single SVG for each element.
  • @jsplumb/connector-bezier The Bezier + StateMachine connectors, which in previous versions were bundled with the core.
  • @jsplumb/connector-flowchart The Flowchart connector, which in previous versions was bundled with the core.
  • @jsplumb/util A set of utility functions used by the Community edition and the Toolkit edition.
  • @jsplumb/common Common definitions and interfaces used by the Community edition and the Toolkit edition.

Initializing jsPlumb#

If you're using jsPlumb alongside a library such as Angular or React then by the time you start interacting with jsPlumb you can be sure that the DOM has fully loaded. However if you're using jsPlumb without some such library, you should not start making calls to jsPlumb until the DOM is ready. To handle this, you should bind to the ready event on the instance of jsPlumb you are working with:

instance.bind("ready", () => {  ...             // your jsPlumb related init code goes here  ...  });

There's a helper method that can save you a few precious characters:

instance.ready(() => {    ...             // your jsPlumb related init code goes here    ...});
note

If you bind to the ready event after jsPlumb has already been initialized, your callback will be executed immediately.

Where does jsPlumb add elements?#

It's important to understand where in the DOM jsPlumb will add any elements it creates. When you create an instance of jsPlumb, you are required to provide a container element, which is the element that will be used as the parent for any element jsPlumb adds to the DOM:

const instance = jsPlumbBrowserUI.newInstance({    container:someDOMElement})

This element should have position:relative set on it via CSS.

tip

If you're experiencing positioning issues with jsPlumb's connections or endpoints, check that you've got position:relative set on your container. jsPlumb uses absolute positioning, which browsers compute relative to their first ancestor that has relative positioning set.

Registering elements#

jsPlumb tracks a set of "managed" elements, for the most part transparently, but in some cases requiring user intervention. When you call addEndpointon some element, the given element is automatically added to the managed list:

instance.addEndpoint(someElement, { endpoint:'Dot' })

Internally, jsPlumb assigns a unique identifier to someElement, and writes it to the element as the value of the data-jtk-managed attribute:

<div data-jtk-managed="7897-42342-4234-4234">your element's content</div>

The presence of this data-jtk-managed element allows jsPlumb to enable dragging for the element, and to handle what happens if it is dragged into or out of a group.

Similarly, when you call connect with one or more elements, those elements are added to the managed list:

instance.connect({    source:someElement,    target:someOtherElement})

Manually registering elements#

Sometimes you might want jsPlumb to begin managing an element before you have configured any endpoints on it, or passed it as an argument to a connect call. This situation is not altogether uncommon, in fact, as when you make use of the addSourceSelector method to configure drag and drop connections in your UI, you most likely will not also be adding endpoints to your individual elements. To assist with this, jsPlumb offers the method manage:

instance.manage(someElement)

manage also supports a second parameter, allowing you to specify the internal ID that jsPlumb should use:

instance.manage(someElement, "the id to use")
caution

It is your responsibility to ensure that the internal ID you request is unique across your dataset. You will get non-deterministic results if you assign a duplicate internal id.


Z-index Considerations#

You need to pay attention to the z-indices of the various parts of your UI when using jsPlumb, in particular to ensure that the elements that jsPlumb adds to the DOM do not overlay other parts of the interface.

jsPlumb adds an element to the DOM for each endpoint, connector and overlay. So for a connection having visible endpoints at each end and a label in the middle, jsPlumb adds four elements to the DOM.

To help you organise z-indices correctly, jsPlumb adds a CSS class to each type of element it adds. They are as follows:

ComponentClass
Endpointjtk-endpoint
Connectorjtk-connector
Overlayjtk-overlay

In addition, whenever the mouse is hovering over an Endpoint or Connection, that component is assigned the class jtk-hover. For more information about styling jsPlumb with CSS, see this page

Performance#

The speed at which jsPlumb executes, and the practical limit to the number of manageable connections, is greatly affected by the browser upon which it is being run. At the time of writing, it will probably not surprise you to learn that jsPlumb runs fastest in Chrome, followed by Safari/Firefox.

Suspending drawing#

Every connect or addEndpoint call in jsPlumb ordinarily causes a repaint of the associated element, which for many cases is what you want. But if you are performing some kind of "bulk" operation - like loading data on page load perhaps - it is recommended that you suspend drawing before doing so:

instance.setSuspendDrawing(true);...- load up all your data here -...instance.setSuspendDrawing(false, true);

Notice the second argument in the last call to setSuspendDrawing: it instructs jsPlumb to immediately perform a full repaint (by calling, internally, repaintEverything).

I said above it is recommended that you do this. It really is. It makes an enormous difference to the load time when you're dealing with a lot of Connections on slower browsers.

The batch method#

This function abstracts out the pattern of suspending drawing, doing something, and then re-enabling drawing:

instance.batch(() => {      // import here  for (let i = 0, j = connections.length; i < j; i++) {      instance.connect(connections[i]);  }  })

Here, we've assumed that connections is an array of objects that would be suitable to pass to the connect method, for example:

{ source:someElement, target:someOtherElement }

By default, this will run a repaint at the end. But you can suppress that, should you want to:

instance.batch(() => {  // import here}, true);