jsPlumb Community edition provides a means for a developer to visually connect elements on their web pages, using SVG, with no external dependencies.
The 1.7.x line of releases were the last ones to support IE8. From version 2.0.0, the Community edition works only in modern browsers that support SVG.
These docs refer to version 2.15.5 of the Community edition and, occasionally, version 2.4.8 of the Toolkit edition.
For Toolkit edition documentation, visit this page.
It is a good idea to read this entire page. There are a few things you need to know about integrating jsPlumb with your UI.
jsPlumb 1.7.x runs on everything from IE6 up. jsPlumb 2.x runs on everything from IE9 up. Touch events are automatically mapped to their mouse equivalents, so binding a click
will work on phones and tablets.
npm install jsplumb
NOTE jsPlumb does not follow the strict rules of semantic versioning. You cannot entrust jsPlumb to release a new version that will work in your software. That is your responsibility. We strongly recommend you do not use wildcards on the jsPlumb import statement, and forego your utopian dreams.
If you're serving your pages with content type text/html
, as most people are, then you should use this doctype:
<!doctype html>
This gives you Standards mode in all browsers and access to HTML5.
No required imports.
<script src="PATH_TO/jsplumb.min.js "></script>
You should not start making calls to jsPlumb until the DOM has been initialized - perhaps no surprises there. To handle this, you should bind to the ready
event on jsPlumb (or the instance of jsPlumb you are working with):
jsPlumb.bind("ready", function() {
...
// your jsPlumb related init code goes here
...
});
There's a helper method that can save you a few precious characters:
jsPlumb.ready(function() {
...
// your jsPlumb related init code goes here
...
});
If you bind to the ready
event after jsPlumb has already been initialized, your callback will be executed immediately.
jsPlumb is registered on the browser's window by default, providing one static instance for the whole page to use. You can also instantiate independent instances of jsPlumb, using the getInstance
method, for example:
var firstInstance = jsPlumb.getInstance();
The variable firstInstance
can now be treated exactly as you would treat the jsPlumb
variable - you can set defaults, call the connect
method, whatever:
firstInstance.importDefaults({
Connector : [ "Bezier", { curviness: 150 } ],
Anchors : [ "TopCenter", "BottomCenter" ]
});
firstInstance.connect({
source:"element1",
target:"element2",
scope:"someScope"
});
getInstance
optionally takes an object that provides the defaults:
var secondInstance = jsPlumb.getInstance({
PaintStyle:{
strokeWidth:6,
stroke:"#567567",
outlineStroke:"black",
outlineWidth:1
},
Connector:[ "Bezier", { curviness: 30 } ],
Endpoint:[ "Dot", { radius:5 } ],
EndpointStyle : { fill: "#567567" },
Anchor : [ 0.5, 0.5, 1, 1 ]
});
secondInstance.connect({
source:"element4",
target:"element3",
scope:"someScope"
});
It is recommended to use separate instances of jsPlumb. When version 4.x is released there will no longer be an instance of jsPlumb available on the window.
jsPlumb uses the id
attribute of any element with which it interacts. If id
is not set, jsPlumb will create an id for the element. It is recommended that you set appropriate ids for the elements in your UI yourself.
Because of the fact that jsPlumb uses element ids, you need to tell jsPlumb if an element id changes. There are two methods to help you do this:
jsPlumb.setId(el, newId)
Use this if you want jsPlumb to take care of changing the id in the DOM. It will do so,
and then update its references accordingly.
jsPlumb.setIdChanged(oldId, newId)
Use this if you have already changed the element's ID, and you just want
jsPlumb to update its references.
Almost every method in jsPlumb that operates on elements supports multiple formats for specifying the element(s) on which to operate.
In the jsPlumb documentation you will see references to the concept of a selector
. This is a list of elements that match some CSS spec. In modern browsers you can get one of these via a call like:
someElement.querySelectorAll('.someSelector')
The native element that querySelectorAll
returns is a NodeList
.
Although jsPlumb has no dependency on jQuery, it also supports jQuery selectors as arguments for elements (vanilla jsPlumb because jQuery's selector object is list-like, ie. it has a length
property and indexed accessors). So this will also work, if you happen to be using jQuery in your page:
jQuery(someElement).find(".someSelector")
Passing a single string as argument will cause jsPlumb to treat that string as an element id.
You can pass DOM elements as arguments. This will probably not surprise you.
You can also pass an array of any or all of the types we just listed. The contents of the array can be mixed - they do not have to be all one type.
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:
Component | Class |
Endpoint | jtk-endpoint |
Connector | jtk-connector |
Overlay | jtk-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.
It's important to understand where in the DOM jsPlumb will add any elements it creates. If you want a TL;DR version, then it boils down to this:
offsetParent
of the first
element on which you call addEndpoint
, makeSource
or makeTarget
, or the offsetParent
of the source element in
the first connect
call - whichever happens first. Note this will not apply from version 4.x onwards, and it's a bad idea anyway. Best to just get in the habit of setting the Container
.var j = jsPlumb.getInstance({
Container:"foo"
});
...
jsPlumb.addEndpoint(someDiv, { endpoint:options });
jsPlumb.setContainer(document.getElementById("foo"));
...
jsPlumb.addEndpoint(someDiv, { endpoint options });
jsPlumb.setContainer("containerId");
...
jsPlumb.connect({ source:someDiv, target:someOtherDiv });
The container you choose should have position:relative
set on it, because it is the origin of that element that jsPlumb will use to compute the placement of the artefacts it adds to the DOM, and jsPlumb uses absolute positioning.
A common feature of interfaces using jsPlumb is that the elements are draggable. You should use jsPlumbInstance.draggable
to configure this:
myInstanceOfJsPlumb.draggable("elementId");
…because if you don't, jsPlumb won't know that an element has been dragged, and it won't repaint the element.
Dragging is covered in detail on this page.
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, and then IE browsers in descending version number order.
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:
jsPlumb.setSuspendDrawing(true);
...
- load up all your data here -
...
jsPlumb.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.
This function abstracts out the pattern of suspending drawing, doing something, and then re-enabling drawing:
jsPlumb.batch(fn, [doNotRepaintAfterwards]);
Example usage:
jsPlumb.batch(function() {
// import here
for (var i = 0, j = connections.length; i < j; i++) {
jsPlumb.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:
jsPlumb.batch(function() {
// import here
}, true);
Note this method used to be called doWhileSuspended
and was renamed in version 1.7.3.
Continuous anchors are the type that require the most maths, because they have to calculate their position every time a paint cycle occurs.
Dynamic and Perimeter anchors are the next slowest (with Perimeter being slower than most Dynamic Anchors as they are actually Dynamic Anchors that have, by default, 60 locations to choose from).
Static anchors like Top
, Bottom
etc are the fastest.