Connections

  1. Programmatic Connections
  2. Drag and Drop Connections
  3. Elements as sources and targets

Programmatic Connections

The most simple connection you can make with jsPlumb looks like this:

jsPlumb.connect({source:"element1", target:"element2"});

In this example we have created a Connection from 'element1' to 'element2'. Remember that a Connection in jsPlumb consists of two Endpoints, a Connector, and zero or more Overlays. But this call to 'connect' supplied none of those things, so jsPlumb uses the default values wherever it needs to. In this case, default values have been used for the following:

So this call will result in an 8px Bezier, colored "#456", from the bottom center of 'element1' to the bottom center of 'element2', and each Endpoint will be a 10px radius Dot Endpoint, colored "#456".

Let's beef up this call a little and tell jsPlumb what sort of Endpoints we want, and where we want them:

jsPlumb.connect({
    source:"element1", 
    target:"element2",
    anchors:["Right", "Left" ],
    endpoint:"Rectangle",
    endpointStyle:{ fillStyle: "yellow" }
});

This is what we have told jsPlumb we want this time:

Reusing common settings between jsPlumb.connect calls

A fairly common situation you will find yourself in is wanting to create a bunch of Connections that have only minor differences between them. To support that, jsPlumb.connect takes an optional second argument. For example:

var common = {
    anchors:[ "BottomCenter", "TopCenter" ],
    endpoints:["Dot", "Blank" ]
};

jsPlumb.connect({ source:"someElement", target:"someOtherElement" }, common);

jsPlumb.connect({ source:"aThirdElement", target:"yetAnotherElement" }, common);
Endpoints created by jsPlumb.connect

If you supply an element id or selector for either the source or target, jsPlumb.connect will automatically create an Endpoint on the given element. These automatically created Endpoints are not marked as drag source or targets, and cannot be interacted with. For some situations this behaviour is perfectly fine, but for more interactive UIs you should set things up using one of the drag and drop methods discussed below.

Note: given that jsPlumb.connect creates its own Endpoints in some circumstances, in order to avoid leaving orphaned Endpoints around the place, if the Connection is subsequently deleted, these automatically created Endpoints are deleted too. Should you want to, you can override this behaviour by setting deleteEndpointsOnDetach to false in the connect call:

jsPlumb.connect({ 
    source:"aThirdElement", 
    target:"yetAnotherElement",
    deleteEndpointsOnDetach:false 
});

Detaching Connections

By default, connections made with jsPlumb.connect will be detachable via the mouse. You can prevent this by either setting an appropriate default value:

jsPlumb.importDefaults({ 
    ...
    ConnectionsDetachable:false
    ...
});

...or by specifying it on the connect call like this:

jsPlumb.connect({ 
    source:"aThirdElement", 
    target:"yetAnotherElement",
    detachable:false
});

Drag and Drop Connections

To support drag and drop connections, you first need to set a few things up. Every drag and drop connection needs at least a source Endpoint that the user can drag a connection from. Here's a simple example of how to create an Endpoint:

var endpointOptions = { isSource:true };
var endpoint = jsPlumb.addEndpoint('elementId', endpointOptions);

This Endpoint will act as a source for new Connections, and will use the jsPlumb defaults for its own appearance and that of any Connections that are drawn from it.

Tip: use the three-argument addEndpoint method for common data

One thing that happens quite often is that you have an Endpoint whose appearance and behaviour is largely the same between usages on different elements, with just a few differences.

var exampleGreyEndpointOptions = {
    endpoint:"Rectangle",
    paintStyle:{ width:25, height:21, fillStyle:'#666' },
    isSource:true,
    connectorStyle : { strokeStyle:"#666" },
    isTarget:true
};

Notice there is no anchor set. Here we apply it to two elements, at a different location in each:

jsPlumb.addEndpoint('element1', { 
    anchor:"BottomCenter" 
}, exampleGreyEndpointOptions)); 

jsPlumb.addEndpoint('element2', { 
    anchor:"TopCenter" 
}, exampleGreyEndpointOptions));        

Now that you have a source Endpoint, you need to either create a target Endpoint on some element, or notify jsPlumb that you wish to make an entire element a drop target. Let's look at how to attach a target Endpoint first:

var endpointOptions = { isTarget:true, endpoint:"Rectangle", paintStyle:{ fillStyle:"gray" } };
var endpoint = jsPlumb.addEndpoint("otherElementId", endpointOptions);

This Endpoint, a gray rectangle, has declared that it can act as a drop target for Connections.

Elements as sources & targets

jsPlumb also supports turning entire elements into Connection sources and targets, using the methods makeSource and makeTarget. With these methods you mark an element as a source or target, and provide an Endpoint specification for jsPlumb to use when a Connection is established. makeSource also gives you the ability to mark some child element as the place from which you wish to drag Connections, but still have the Connection on the main element after it has been established.

These methods honour the jsPlumb defaults - if, for example you set up the default Anchors to be this:

jsPlumb.Defaults.Anchors = [ "LeftMiddle", "BottomRight" ];

... and then used makeSource and makeTarget without specifying Anchor locations, jsPlumb would use LeftMiddle for the makeSource element and BottomRight for the makeTarget element.

A further thing to note about makeSource and makeTarget is that any prior calls to one of these methods is honoured by subsequent calls to jsPlumb.connect. This helps when you're building a UI that uses this functionality at runtime but which loads some initial data, and you want the statically loaded data to have the same appearance and behaviour as dynamically created Connections (obviously quite a common use case).

For example:

jsPlumb.makeSource("el1", {
    anchor:"Continuous",
    endpoint:["Rectangle", { width:40, height:20 }],
    maxConnections:3
});

...

jsPlumb.connect({source:"el1", target:"el2"});

In this example, the source of the connection will be a Rectangle of size 40x20, having a Continuous Anchor. The source is also configured to allow a maximum of three Connections.

You can override this behaviour by setting a newConnection parameter on the connect call:

jsPlumb.makeSource("el1", {
    anchor:"Continuous",
    endpoint:["Rectangle", { width:40, height:20 }],
    maxConnections:1,
    onMaxConnections:function(info, originalEvent) {
        console.log("element is ", info.element, "maxConnections is", info.maxConnections);    
    }
});

...

jsPlumb.connect({ 
  source:"el1", 
  target:"el2", 
  newConnection:true 
});

Note the onMaxConnections parameter to this call - it allows you to supply a function to call if the user tries to drag a new Connection when the source has already reached capacity.

jsPlumb.makeTarget

This method takes two arguments, the first of which specifies some element (or list of elements); the second specifies the Endpoint you wish to create on that element whenever a Connection is established on it. In this example we will use the exact same target Endpoint we used before - the gray rectangle - but we will tell jsPlumb that the element aTargetDiv will be the drop target:

var endpointOptions = { 
  isTarget:true, 
  maxConnections:5,
  endpoint:"Rectangle", 
  paintStyle:{ fillStyle:"gray" } 
};
jsPlumb.makeTarget("aTargetDiv", endpointOptions);

The allowed values in 'endpointOptions' are identical for both the jsPlumb.addEndpoint and jsPlumb.makeTarget methods, but makeTarget supports an extended Anchor syntax that allows you more control over the location of the target endpoint. This is discussed below.

Notice in the endpointOptions object above there is a parameted called isTarget - this may seem incongruous, since you know you're going to make some element a target. Remember that the endpointOptions object is the information jsPlumb will use to create an Endpoint on the given target element each time a Connection is established to it. It takes the exact same format as you would pass to addEndpoint; makeTarget is essentially a deferred addEndpoint call followed by a connect call. So in this case, we're telling jsPlumb that any Endpoints it happens to create on some element that was configured by the makeTarget call are themselves Connection targets. You may or may not want this behaviour in your application - just control it by setting the approriate value for that parameter (it defaults to false).

makeTarget also supports the maxConnections and onMaxConnections parameters, as makeSource does, but note that onMaxConnections is passed one extra parameter than its corresponding callback from makeSource - the Connection the user tried to drop:

jsPlumb.makeTarget("aTargetDiv", { 
  isTarget:true, 
  maxConnections:5,
  endpoint:"Rectangle", 
  paintStyle:{ fillStyle:"gray" },
  maxConnections:3,
  onMaxConnections:function(info, originalEvent) {
    console.log("user tried to drop connection", info.connection, "on element", info.element, "with max connections", info.maxConnections);
  }
};
Unique Endpoint per Target

jsPlumb will create a new Endpoint using the supplied information every time a new Connection is established on the target element, by default, but you can override this behaviour and tell jsPlumb that it should create at most one Endpoint, which it should attempt to use for subsequent Connections:

var endpointOptions = { 
  isTarget:true, 
  uniqueEndpoint:true,
  endpoint:"Rectangle", 
  paintStyle:{ fillStyle:"gray" } 
};
jsPlumb.makeTarget("aTargetDiv", endpointOptions);

Here, the uniqueEndpoint parameter tells jsPlumb that there should be at most one Endpoint on this element. Notice that maxConnections is not set: the default is 1, so in this setup we have told jsPlumb that aTargetDiv can receive one Connection and no more.

Deleting Endpoints on Detach

By default, any Endpoints created using makeTarget have deleteEndpointsOnDetach set to true, which means that once all Connections to that Endpoint are removed, the Endpoint is deleted. You can override this by setting the flag to true on the makeTarget call:

var endpointOptions = { 
  isTarget:true, 
  maxConnections:5,
  uniqueEndpoint:true,
  deleteEndpointsOnDetach:false,
  endpoint:"Rectangle", 
  paintStyle:{ fillStyle:"gray" } 
};
jsPlumb.makeTarget("aTargetDiv", endpointOptions);

In this setup we have told jsPlumb to create an Endpoint the first time aTargetElement receives a Connection, and to not delete it even if there are no longer any Connections to it. The created Endpoint will be reused for subsequent Connections, and can support a maximum of 5.

Detaching connections made with the mouse

As with jsPlumb.connect, Connections made with the mouse after setting up Endpoints with one of the functions we've just covered will be, by default, detachable. You can prevent this in the jsPlumb defaults, as previously mentioned:

jsPlumb.importDefaults({ 
    ...
    ConnectionsDetachable:false,
    ...
});

And you can also set this on a per-endpoint (or source/target) level, like in these examples:

jsPlumb.addEndpoint("someElementId", { 
    connectionsDetachable:false    
});

jsPlumb.makeSource("someOtherElement", {
    ...
    connectionsDetachable:false,
    ...
});

jsPlumb.makeTarget("yetAnotherElement", {
    ...
    connectionsDetachable:false,
    ...
});

Note that in the jsPlumb defaults, by convention each word in a parameter is capitalised ("ConnectionsDetachable"), whereas for a call to one of these methods, we use camel case ("connectionsDetachable").

Target Anchors positions with makeTarget

When using the makeTarget method, jsPlumb allows you to provide a callback function to be used to determine the appropriate location of a target Anchor for every new Connection dropped on the given target. It may be the case that you want to take some special action rather than just relying on one of the standard Anchor mechanisms.

This is achieved through an extended Anchor syntax (note that this syntax is not supported in the jsPlumb.addEndpoint method) that supplies a "positionFinder" to the anchor specification. jsPlumb provides two of these by default; you can register your own on jsPlumb and refer to them by name, or just supply a function. Here's a few examples:

jsPlumb.makeTarget("someElement", {
  anchor:[ "Assign", { 
    position:"Fixed"
  }]
});
`Fixed` is one of the two default position finders provided by jsPlumb. The other is `Grid`:
jsPlumb.makeTarget("someElement", {
  anchor:[ "Assign", { 
    position:"Grid",
    grid:[3,3]
  }]
});

The Grid position finder takes a grid parameter that defines the size of the grid required. [3,3] means 3 rows and 3 columns.

Supplying your own position finder

To supply your own position finder to jsPlumb you first need to create the callback function. First let's take a look at what the source code for the Grid position finder looks like:

function(eventOffset, elementOffset, elementSize, constructorParams) {
  var dx = eventOffset.left - elementOffset.left, dy = eventOffset.top - elementOffset.top,
      gx = elementSize[0] / (constructorParams.grid[0]), 
      gy = elementSize[1] / (constructorParams.grid[1]),
      mx = Math.floor(dx / gx), my = Math.floor(dy / gy);

  return [ ((mx * gx) + (gx / 2)) / elementSize[0], ((my * gy) + (gy / 2)) / elementSize[1] ];
}

The four arguments are: - eventOffset - Page left/top where the mouse button was released (a JS object containing left/top members like you get from a jQuery offset call) - elementOffset - JS offset object containing offsets for the element on which the Connection is to be created - elementSize - [width, height] array of the dimensions of the element on which the Connection is to be created - constructorParams - the parameters that were passed to the Anchor's constructor. In the example given above, those parameters are 'position' and 'grid'; you can pass arbitrary parameters.

The return value of this function is an array of [x, y] - proportional values between 0 and 1 inclusive, such as you can pass to a static Anchor.

To make your own position finder you need to create a function that takes those four arguments and returns an [x, y] position for the anchor, for example:

jsPlumb.AnchorPositionFinders.MyFinder = function(dp, ep, es, params) {
  ... do some maths ...    
  console.log("my custom parameter is ", params.myCustomParameter);
  return [ x, y ];    
};
Then refer to it in a makeTarget call:
jsPlumb.makeTarget("someElement", {  
  anchor:[ "Assign", { 
    position:"MyFinder",
    myCustomParameter:"foo",
    anInteger:5
  }]
});

jsPlumb.makeSource

There are two use cases supported by this method. The first is the case that you want to drag a Connection from the element itself and have an Endpoint attached to the element when a Connection is established. The second is a more specialised case: you want to drag a Connection from the element, but once the Connection is established you want jsPlumb to move it so that its source is on some other element.

Here's an example code snippet for the basic use case of makeSource:

jsPlumb.makeSource(someDiv, {
  paintStyle:{ fillStyle:"yellow" },
  endpoint:"Blank",
  anchor:"BottomCenter"
});

Notice again that the second argument is the same as the second argument to an addEndpoint call. makeSource is, essentially, a type of addEndpoint call. In this example we have told jsPlumb that we will support dragging Connections directly from someDiv. Whenever a Connection is established between someDiv and some other element, jsPlumb assigns an Endpoint at BottomCenter of someDiv, fills it yellow, and sets that Endpoint as the newly created Connection's source.

Specifying drag source area

Configuring an element to be an entire Connection source using makeSource means that the element cannnot itself be draggable. There would be no way for jsPlumb to distinguish between the user attempting to drag the element and attempting to drag a Connection from the element. jsPlumb has two ways for you to handle this. Why two? The second one didn't occur to me until later. The first one will probably be discontinued at some stage.

Supplying a 'parent' parameter

In this code snippet, note the parent parameter. It instructs jsPlumb to configure the source Endpoint on the element specified - in this case, someDiv (the value of this parameter may be a String id or a selector).

jsPlumb.makeSource("someConnectionSourceDiv", {
  paintStyle:{ fillStyle:"yellow" },
  endpoint:"Blank",
  anchor:"BottomCenter",
  parent:"someDiv"
});

If you just want to say "use the parent of this element", you can supply "parent":

jsPlumb.makeSource("someConnectionSourceDiv", {
  paintStyle:{ fillStyle:"yellow" },
  endpoint:"Blank",
  anchor:"BottomCenter",
  parent:"parent"
});

This was the original way of handling the makeSource drag conundrum in jsPlumb, but it's not as good as supplying a filter parameter, which is discussed below. The main problem is that when you use this mechanism you don't actually register the makeSource call on the element you want; instead you register it on some child of that element and supply the element you're really configuring as parent. It's just not quite 'right', conceptually.

Supplying a filter parameter

The second way to handle the drag problem makes much more sense:you supply a 'filter' parameter to the makeSource call, which can be either a function object or a selector. Consider this markup:

<div id="foo">
  FOO
  <button>click me</button>
<div>

Suppose we do not want to interfere with the operation of the "click me" button. We can supply a filter to the makeSource call to do so:

jsPlumb.makeSource("foo", {
  filter:":not(button)"
});

or

jsPlumb.makeSource("foo", {
  filter:function(event, element) {
    return event.target.tagName !== "BUTTON";
  }
});

In this second example, if the filter returns anything other than a boolean false, the drag will begin. It's important to note that only boolean false will prevent a drag. False-y values will not.

Endpoint options with makeSource

There are many things you can set in an Endpoint options object; for a thorough list see the API documentation for Endpoint.

Here's an example of specifying that you want an Arrow overlay halfway along any Connection dragged from this Endpoint:

var exampleGreyEndpointOptions = {
  endpoint:"Rectangle",
  paintStyle:{ width:25, height:21, fillStyle:'#666' },
  isSource:true,
  connectorStyle : { strokeStyle:"#666" },
  isTarget:true,
  connectorOverlays: [ [ "Arrow", { location:0.5 } ] ]
};

This is an Endpoint that moves around the element it is attached to dependent on the location of other elements in the connections it is attached to (a 'dynamic' anchor):

var exampleGreyEndpointOptions = {
  endpoint:"Rectangle",
  paintStyle:{ width:25, height:21, fillStyle:'#666' },
  isSource:true,
  connectorStyle : { strokeStyle:"#666" },
  isTarget:true,
  connectorOverlays: [ [ "Arrow", { location:0.5 } ] ]
  anchor:[ "TopCenter","RightMiddle","BottomCenter","LeftMiddle" ]
};
Testing if an element is a target or source

You can test if some element has been made a connection source or target using these methods:

The return value is a boolean.

Toggling an element as connection target or source

You can toggle the state of some source or target using these methods:

The return value from these methods is the current jsPlumb instance, allowing you to chain them:

jsPlumb.setTargetEnabled("aDivId").setSourceEnabled($(".aSelector"));

Note that if you call either of these methods on an element that was not originally configured as a target or source, nothing will happen.

You can check the enabled state of some target or source using these methods:

Canceling previous makeTarget and/or makeSource calls

jsPlumb offers four methods to let you cancel previous makeTarget or makeSource calls. Each of these methods returns the current jsPlumb instance, and so can be chained:

These last two are analogous to the removeEveryConnection and deleteEveryEndpoint methods that have been in jsPlumb for a while now.

unmakeTarget and unmakeSource both take as argument the same sorts of values that makeTarget and makeSource accept - a string id, or a selector, or an array of either of these:

jsPlumb.unmakeTarget("aDivId").unmakeSource($(".aSelector"));
Drag Options

These are options that will be passed through to the supporting library's drag API. jsPlumb passes everything you supply here through, inserting wrapping functions if necessary for the various lifecycle events that jsPlumb needs to know about. So if, for example, you pass a function to be called when dragging starts, jsPlumb will wrap that function with a function that does what jsPlumb needs to do, then call yours.

At the time of writing, jsPlumb supports jQuery, MooTools and YUI3, and each of those libraries uses different terminology. In addition, jQuery's API is more fully featured, providing easy support for setting the zIndex and opacity of elements being dragged, as well as the 'scope' for a drag/drop (allowing you to specify more than one type of drag/drop pair), and hover classes for when a draggable is on the move or over a droppable. If you're using jQuery you can of course just supply these values on the dragOptions; to make it easier, jsPlumb's MooTools and YUI3 adapters recognize these options and add appropriate callbacks for you.

Given that the options here are library-specific, and they are all well-documented, we're going to discuss just the three drag options that behave the same way in all (see below for hoverClass):

For more information about drag options, take a look at the jQuery, MooTools, or YUI3 docs.

Drop Options

Drop options are treated by jsPlumb in the same way as drag options - they are passed through to the underlying library. MooTools does not have drop options like jQuery and YUI3 do; droppable functionality in MooTools is actually implemented by the Drag.Move class - the one used to initialise a draggable. But when you setup an Endpoint in jsPlumb you should ignore that fact, and treat droppables like you would in jQuery or YUI3. jsPlumb wires everything up for you under the hood.

There are three jQuery droppable options that jsPlumb treats as shortcuts in MooTools and YUI3, for the sake of consistency:

For more information about drop options when using jQuery, see here

Drag and Drop Scope

jsPlumb borrowed the concept of 'scope' from jQuery's drag/drop implementation: the notion of which draggables can be dropped on which droppables. In jsPlumb you can provide a 'scope' entry when creating an Endpoint. Here's the example grey Endpoint example with 'scope' added:

var exampleGreyEndpointOptions = {
  endpoint:"Rectangle",
  paintStyle:{ width:25, height:21, fillStyle:"#666" },
  isSource:true,
  connectionStyle : { strokeStyle:"#666" },
  isTarget:true,
  scope:"exampleGreyConnection"
};

If you do not provide a 'scope' entry, jsPlumb uses a default scope. Its value is accessible through this method:

jsPlumb.getDefaultScope();

If you want to change it for some reason you can do so with this method:

jsPlumb.setDefaultScope("mySpecialDefaultScope");

You can also, should you want to, provide the scope value separately on the drag/drop options, like this:

var exampleGreyEndpointOptions = {
  endpoint:"Rectangle",
  paintStyle:{ width:25, height:21, fillStyle:'#666' },
  isSource:true,
  connectionStyle : { strokeStyle:"#666" },
  isTarget:true,
  dragOptions:{ scope:"dragScope" },
  dropOptions:{ scope:"dropScope" }
};

Disconnecting and Reconnecting

By default, jsPlumb will allow you to detach connections from either Endpoint by dragging (assuming the Endpoint allows it; Blank Endpoints, for example, have nothing you can grab with the mouse). If you then drop a Connection you have dragged off an Endpoint, the Connection will be detached. This behaviour can be controlled using the detachable and reattachparameters, or their equivalents in the jsPlumb Defaults.

Some examples should help explain:

This behaviour can also be controlled using jsPlumb defaults:

jsPlumb.importDefaults({
  ConnectionsDetachable:true,
  ReattachConnections:true
});

The default value of ConnectionsDetachable is true, and the default value of ReattachConnections is false, so in actual fact those defaults are kind of pointless. But you probably get the point.

Setting detachable/reattach on Endpoints

Endpoints support the 'detachable' and 'reattach' parameters too. If you create an Endpoint and mark 'detachable:false', then all Connections made from that Endpoint will not be detachable. However, since there are two Endpoints involved in any Connection, jsPlumb takes into account the 'detachable' and 'reattach' parameters from both Endpoints when establishing a Connection. If either Endpoint declares either of these values as true, jsPlumb assumes the value to be true. It is possible that in a future version of jsPlumb the concepts of detachable and reattach could be made more granular, through the introduction of parameters like sourceDetachable/targetReattach etc.

Dropping a dragged Connection on another Endpoint

If you drag a Connection from its target Endpoint you can then drop it on another suitable target Endpoint - suitable meaning that it is of the correct scope and it is not full. If you try to drop a Connection on another target that is full, the drop will be aborted and then the same rules will apply as if you had dropped the Connection in whitespace: if 'reattach' is set, the Connection will reattach, otherwise it will be removed.

You can drag a Connection from its source Endpoint, but you can only drop it back on its source Endpoint - if you try to drop it on any other source or target Endpoint jsPlumb will treat the drop as if it happened in whitespace. Note that there is an issue with the hoverClass parameter when dragging a source Endpoint: target Endpoints are assigned the hover class, as if you could drop there. But you cannot; this is caused by how jsPlumb uses the underlying library's drag and drop, and is something that will be addressed in a future release.