Skip to main content
Version: 4.1

linkTools

A link tool is a view that renders a certain type of control elements on top of the LinkView it is attached to; for example the Vertices tool creates an interactive handle above every vertex (these handles then allow the user to move and/or delete each vertex). Link tools all inherit from the joint.dia.ToolView class. A collection of tools is added to a ToolsView; a tools view is then added to the linkView with the linkView.addTools() function.

The JointJS library comes with a collection of pre-made link tool definitions in the joint.linkTools namespace:

To create a new link tool, we call its constructor. Example:

var verticesTool = new joint.linkTools.Vertices({
snapRadius: 10
});

In addition, the joint.linkTools namespace contains a customizable button class:

Example:

var infoTool = new joint.linkTools.Button({
markup: [{
tagName: 'circle',
selector: 'button',
attributes: {
'r': 7,
'fill': '#001DFF',
'cursor': 'pointer'
}
}, {
tagName: 'path',
selector: 'icon',
attributes: {
'd': 'M -2 4 2 4 M 0 3 0 0 M -2 -1 1 -1 M -1 -4 1 -4',
'fill': 'none',
'stroke': '#FFFFFF',
'stroke-width': 2,
'pointer-events': 'none'
}
}],
distance: 60,
offset: 0,
action: function(evt) {
alert('View id: ' + this.id + '\n' + 'Model id: ' + this.model.id);
}
});

All of the built-in link tools accept the following optional argument, in addition to their own arguments:

focusOpacitynumberWhat should be the opacity of the tool when it is focused (e.g. with the toolView.focus function)? Default is undefined, meaning that the tool's opacity is kept unchanged.

Example:

var verticesTool = new joint.linkTools.Vertices({
focusOpacity: 0.5
});

Classes​

Boundary​

The Boundary link tool renders a rectangular border to show the bounding box of the link. It accepts a few additional arguments, which can be passed as an object to the link tool constructor:

paddingnumber|objectThis option determines whether the boundary area should be visually inflated and if so, by how much. Default is 10 ({ left: 10, top: 10, right: 10, bottom: 10 }).
useModelGeometrybooleanIf this option is set to true, the position of the boundary is calculated based on the dimensions of the link model.

Example:

var boundaryTool = new joint.linkTools.Boundary({
focusOpacity: 0.5,
padding: 20,
useModelGeometry: true
});

Button​

The Button link tool allows you to have a custom button rendered at a given position along the link. It accepts five additional arguments, which can be passed as an object to the link tool constructor:

distancenumberDistance at which the button should be placed. Negative numbers are accepted; then the distance is counted from the end of the link. Default is 0.
stringPercentage strings (e.g. '40%') are also accepted.
function

The callback function is expected to have the signature function(linkView, toolView) where linkView is the link view with the tool attached. The button view is available inside the function as this and as the last parameter. The function should return a number or a string.

(linkView) => (linkView.getConnectionLength() < 100) ? '50%' : -20;
rotatebooleanShould the button rotate according to the slope of the link at the position specified by distance? Default is false.
offsetnumberRelative offset of the button from the link. Positive numbers mean that the button should be offset to the right of the link (relative to the direction from source to target); negative numbers mean that the button should be offset to the left of the link (relative to the direction from source to target). Default is 0.
actionfunctionWhat should happen when the user clicks the button? Default is undefined (no interaction).

The callback function is expected to have the signature function(evt, linkView, buttonView) where evt is a DOM event. The related link view is available inside the function as this. The link model is available as this.model.
markupJSONMarkupThe markup of the button, provided in the JointJS JSON format. Default is undefined (no content).
scalenumberScale the button up or down on a 2D plane. The default is 1.

Example of a useful custom info button:

var infoButton = new joint.linkTools.Button({
focusOpacity: 0.5,
distance: 60,
action: function(evt) {
alert('View id: ' + this.id + '\n' + 'Model id: ' + this.model.id);
},
markup: [{
tagName: 'circle',
selector: 'button',
attributes: {
'r': 7,
'fill': '#001DFF',
'cursor': 'pointer'
}
}, {
tagName: 'path',
selector: 'icon',
attributes: {
'd': 'M -2 4 2 4 M 0 3 0 0 M -2 -1 1 -1 M -1 -4 1 -4',
'fill': 'none',
'stroke': '#FFFFFF',
'stroke-width': 2,
'pointer-events': 'none'
}
}]
});

The linkTools.Button class can also be extended, to create a reusable custom button type. Then, a new instance of the custom button type can be obtained by calling its constructor:

var InfoButton = joint.linkTools.Button.extend({
name: 'info-button',
options: {
focusOpacity: 0.5,
distance: 60,
action: function(evt) {
alert('View id: ' + this.id + '\n' + 'Model id: ' + this.model.id);
},
markup: [{
tagName: 'circle',
selector: 'button',
attributes: {
'r': 7,
'fill': '#001DFF',
'cursor': 'pointer'
}
}, {
tagName: 'path',
selector: 'icon',
attributes: {
'd': 'M -2 4 2 4 M 0 3 0 0 M -2 -1 1 -1 M -1 -4 1 -4',
'fill': 'none',
'stroke': '#FFFFFF',
'stroke-width': 2,
'pointer-events': 'none'
}
}]
}
});

var infoButton = new InfoButton();

Connect​

The Connect tool allows the user to create links in a drag & drop fashion. The tool extends the Button tool and accepts additional arguments, which can be passed as an object to the connect tool constructor:

magnetstring
SVGElement
(view: dia.ElementView) => SVGElement

Choose the source magnet of the element view which the new link should be connected to.

'body' // as a string Selector
linkView.el // as an SVGElement
(linkView) => linkView.el // as a function

The callback function is expected to have the signature function(elementView, toolView) where elementView is the element view with the tool attached. The connect button view is available inside the function as this and as the last parameter.

Example:

const connectButton = new joint.linkTools.Connect({
rotate: true,
distance: -20,
offset: 20,
magnet: 'body'
});

HoverConnect​

The HoverConnect tool allows the user to create links from other links in a drag & drop fashion. The tool extends the Connect tool. The difference is that the button appears along the invisible track path (in the shape of a linkView) at the point where the user moves the mouse over the track. It accepts additional arguments, which can be passed as an object to the hover connect tool constructor:

trackWidthnumberThe thickness of the track path. The default is 15.

Example:

const hoverButton = new joint.linkTools.HoverConnect({
magnet: 'body',
trackWidth: 10
});

Remove​

The Remove link tool renders a remove button at a given position along the link. It accepts five additional arguments, which can be passed as an object to the link tool constructor:

distancenumber

Distance at which the button should be placed. Negative numbers are accepted; then the distance is counted from the end of the link. Default is 60.

stringPercentage strings (e.g. '40%') are also accepted.
rotatebooleanShould the button rotate according to the slope of the link at the position specified by distance? Default is false.
offsetnumber

Relative offset of the button from the link. Positive numbers mean that the button should be offset to the right of the link (relative to the direction from source to target); negative numbers mean that the button should be offset to the left of the link (relative to the direction from source to target). Default is 0.

actionfunction

What should happen when the user clicks the remove button? Default:

function(evt, linkView, toolView) {
linkView.model.remove({ ui: true, tool: toolView.cid });
}

The callback function is expected to have the signature function(evt) where evt is a DOM event. The button view is available inside the function as this; the button model is available as this.model.

markupJSONMarkup

The markup of the button, provided in the JointJS JSON format. Default:

[{
tagName: 'circle',
selector: 'button',
attributes: {
'r': 7,
'fill': '#FF1D00',
'cursor': 'pointer'
}
}, {
tagName: 'path',
selector: 'icon',
attributes: {
'd': 'M -3 -3 3 3 M -3 3 3 -3',
'fill': 'none',
'stroke': '#FFFFFF',
'stroke-width': 2,
'pointer-events': 'none'
}
}]
scalenumberScale the button up or down on a 2D plane. The default is 1.

Example:

var removeButton = new joint.linkTools.Remove({
focusOpacity: 0.5,
rotate: true,
distance: -20,
offset: 20
});

Segments​

The Segments link tool renders handles above all segments of the link (as determined by the link connector). It accepts four additional arguments, which can be passed as an object to the link tool constructor:

redundancyRemovalbooleanIf the user arranges two (or more) segments so that they lie on a single line, should the middle one(s) be considered redundant and removed? Default is true. Note that this setting is not applied until the user actually moves one of the segments in question; this means that segments can still be arranged in this redundant fashion, using the link.vertices function, for example.
segmentLengthThresholdnumberThe minimum segment length for which to display a segment handle (to prevent the handle from overflowing its segment). Default is 40.
snapRadiusnumberWhile the user is moving the segment, from how far away should the segment snap in order to arrange itself in line with another segment? Default is 10.
snapHandlenumberIf the snapRadius option is set to true and the segment is snapped in place while the user moves the segment handle, should the handle follow the user pointer or should the handle stay snapped with the segment until it un-snaps? Default is true, meaning that the handle snaps with the segment.
stopPropagationbooleanShould be events stopped from propagating to the paper? Default is true.
handleClassmvc.ViewThe view for the segment handle. By default it uses linkTools.Segments.SegmentHandle class.
scalenumberScale the segment handles up or down on a 2D plane. The default is 1.

The tool is meant to be used with normal router only. It does not work with e.g. orthogonal router. It throws the "Segments: incompatible router in use" error if used with any other router.

Example:

var segmentsTool = new joint.linkTools.Segments({
focusOpacity: 0.5,
redundancyRemoval: false,
segmentLengthThreshold: 50,
snapHandle: false,
snapRadius: 10
});

SourceAnchor​

The SourceAnchor link tool renders a handle above the source anchor of the link (as determined by the anchor function applied on link source). It accepts several additional arguments, which can be passed as an object to the link tool constructor:

redundancyRemovalbooleanIf the user moves the anchor so that it lies on a single line with two (or more) vertices, should the middle one(s) be considered redundant and removed? Default is true. Note that this setting is not applied until the user actually moves the anchor; this means that the anchor and vertices can still be arranged in this redundant fashion, using the link.vertices function, for example.
restrictAreabooleanShould the user only be allowed to move the anchor in a restricted area (the area of the bounding box of the source magnet)? Default is true.
areaPaddingnumberIf the restrictArea option is set to true, the user can only move the anchor in a restricted area (the area of the bounding box of the source magnet). JointJS shows this restriction by drawing a boundary around that area. This option determines whether this boundary area should be visually inflated and if so, by how much. Default is 10. Note that this is a purely cosmetic setting; regardless of the provided value, the movement stays restricted to the original uninflated bounding box.
snapRadiusnumberWhile the user is moving the anchor, from how far away should the segment snap in order to arrange itself in line with the anchor reference? Default is 10. (For link source, the anchor reference is the first vertex. If there are no vertices, it is the target anchor.)
resetAnchorboolean | objectWhen the user double clicks the anchor tool, the following action should be performed:
  • true - remove the current source anchor from the link. It is a default.
  • false - do nothing
  • { name: [AnchorName], args: [AnchorArguments] } - replace the current source anchor with the option value.
snapfunctionWhat snap function should be applied when the user moves the anchor? Default is a simple function that emulates the snapping behavior of Vertices and Segments link tools: If the value of one of the user pointer coordinates is within snapRadius of the value of a coordinate of the anchor reference, snap to the reference value. (For link source, the anchor reference is the first vertex. If there are no vertices, it is the target anchor.)

The callback function must return the anchor as a g.Point and have the signature function(coords, endView, endMagnet, endType, linkView, toolView):

coordsg.PointA Point object recording the x-y coordinates of the user pointer when the snap function was invoked.
endViewdia.ElementViewThe ElementView which contains the restricted area. The Element model can be accessed as endView.model; this may be useful for writing conditional logic based on element attributes.
endMagnetSVGElementThe SVGElement in our page that contains the magnet (element/subelement/port) which serves as the restricted area.
endTypestringIs the end view the source ('source') or target ('target') of the link?
linkViewdia.LinkViewThe LinkView to which the tool is attached. The Link model can be accessed as linkView.model; this may be useful for writing conditional logic based on link attributes.
toolViewdia.ToolViewThis tool. May be useful for writing conditional logic based on tool options (e.g. the default algorithm refers to toolView.options.snapRadius).
scalenumberScale the anchor element up or down on a 2D plane. The default is 1.

Example:

var sourceAnchorTool = new joint.linkTools.SourceAnchor({
focusOpacity: 0.5,
redundancyRemoval: false,
restrictArea: false,
snapRadius: 20
});

An example of a useful custom snap function is provided below. It snaps the anchor to the center of the closest side of the restricted area.

var snapAnchor = function(coords, endView, endMagnet) {

// remove rotation of the restricted area
var bbox = endView.getNodeUnrotatedBBox(endMagnet);
var angle = endView.model.angle();
var origin = endView.model.getBBox().center();
coords.rotate(origin, angle);

// identify the side nearest to pointer coords
var anchor;
var side = bbox.sideNearestToPoint(coords);
switch (side) {
case 'left': anchor = bbox.leftMiddle(); break;
case 'right': anchor = bbox.rightMiddle(); break;
case 'top': anchor = bbox.topMiddle(); break;
case 'bottom': anchor = bbox.bottomMiddle(); break;
}

// rotate the anchor according to original rotation of restricted area
return anchor.rotate(origin, -angle);
};

var sourceAnchorTool = new joint.linkTools.SourceAnchor({
snap: snapAnchor;
});

If the user moves the anchor away from its original position, the anchor position may be reset by double-clicking the anchor handle.

SourceArrowhead​

The SourceArrowhead link tool renders an arrow-like handle above the source connection point of the link (as determined by the connectionPoint function applied on link source). It accepts a few additional arguments, which can be passed as an object to the link tool constructor:

scalenumberScale the arrowhead element up or down on a 2D plane. The default is 1.

Example:

var sourceArrowheadTool = new joint.linkTools.SourceArrowhead({
focusOpacity: 0.5
});

TargetAnchor​

The TargetAnchor link tool renders a handle above the target anchor of the link (as determined by the anchor function applied on link target). It accepts several additional arguments, which can be passed as an object to the link tool constructor:

redundancyRemovalbooleanIf the user moves the anchor so that it lies on a single line with two (or more) vertices, should the middle one(s) be considered redundant and removed? Default is true. Note that this setting is not applied until the user actually moves the anchor; this means that the anchor and vertices can still be arranged in this redundant fashion, using the link.vertices function, for example.
restrictAreabooleanShould the user only be allowed to move the anchor in a restricted area (the area of the bounding box of the target magnet)? Default is true.
areaPaddingnumberIf the restrictArea option is set to true, the user can only move the anchor in a restricted area (the area of the bounding box of the target magnet). JointJS shows this restriction by drawing a boundary around that area. This option determines whether this boundary area should be visually inflated and if so, by how much. Default is 10. Note that this is a purely cosmetic setting; regardless of the provided value, the movement stays restricted to the original uninflated bounding box.
snapRadiusnumberWhile the user is moving the anchor, from how far away should the segment snap in order to arrange itself in line with the anchor reference? Default is 10. (For link target, the anchor reference is the last vertex. If there are no vertices, it is the source anchor.)
resetAnchorboolean | objectWhen the user double clicks the anchor tool, the following action should be performed:
  • true - remove the current target anchor from the link. It is a default.
  • false - do nothing
  • { name: [AnchorName], args: [AnchorArguments] } - replace the current target anchor with the option value.
snapfunctionWhat snap function should be applied when the user moves the anchor? Default is a simple function that emulates the snapping behavior of Vertices and Segments link tools: If the value of one of the user pointer coordinates is within snapRadius of the value of a coordinate of the anchor reference, snap to the reference value. (For link target, the anchor reference is the last vertex. If there are no vertices, it is the source anchor.)

The callback function must return the anchor as a g.Point and have the signature function(coords, endView, endMagnet):

coordsg.PointA Point object recording the x-y coordinates of the user pointer when the snap function was invoked.
endViewdia.ElementViewThe ElementView which contains the restricted area. The Element model can be accessed as endView.model; this may be useful for writing conditional logic based on element attributes.
endMagnetSVGElementThe SVGElement in our page that contains the magnet (element/subelement/port) which serves as the restricted area.
endTypestringIs the end view the source ('source') or target ('target') of the link?
linkViewdia.LinkViewThe LinkView to which the tool is attached. The Link model can be accessed as linkView.model; this may be useful for writing conditional logic based on link attributes.
toolViewdia.ToolViewThis tool. May be useful for writing conditional logic based on tool options (e.g. the default algorithm refers to toolView.options.snapRadius).
scalenumberScale the anchor element up or down on a 2D plane. The default is 1.

Example:

var targetAnchorTool = new joint.linkTools.TargetAnchor({
focusOpacity: 0.5,
redundancyRemoval: false,
restrictArea: false,
snapRadius: 20
});

An example of a useful custom snap function is provided below. It snaps the anchor to the center of the closest side of the restricted area.

var snapAnchor = function(coords, endView, endMagnet) {

// remove rotation of the restricted area
var bbox = endView.getNodeUnrotatedBBox(endMagnet);
var angle = endView.model.angle();
var origin = endView.model.getBBox().center();
coords.rotate(origin, angle);

// identify the side nearest to pointer coords
var anchor;
var side = bbox.sideNearestToPoint(coords);
switch (side) {
case 'left': anchor = bbox.leftMiddle(); break;
case 'right': anchor = bbox.rightMiddle(); break;
case 'top': anchor = bbox.topMiddle(); break;
case 'bottom': anchor = bbox.bottomMiddle(); break;
}

// rotate the anchor according to original rotation of restricted area
return anchor.rotate(origin, -angle);
};

var targetAnchorTool = new joint.linkTools.TargetAnchor({
snap: snapAnchor;
});

If the user moves the anchor away from its original position, the anchor position may be reset by double-clicking the anchor handle.

TargetArrowhead​

The TargetArrowhead link tool renders an arrow-like handle above the target connection point of the link (as determined by the connectionPoint function applied on link target). It accepts a few additional arguments, which can be passed as an object to the link tool constructor:

scalenumberScale the arrowhead element up or down on a 2D plane. The default is 1.

Example:

var targetArrowheadTool = new joint.linkTools.TargetArrowhead({
focusOpacity: 0.5
});

Vertices​

The Vertices link tool renders handles above all vertices of the link. It accepts three additional arguments, which can be passed as an object to the link tool constructor:

redundancyRemovalbooleanIf the user arranges three (or more) vertices so that they lie on a single line, should the middle one(s) be considered redundant and removed? Default is true. Note that this setting is not applied until the user actually moves one of the vertices in question; this means that vertices can still be arranged in this redundant fashion, using of the link.vertices function, for example.
snapRadiusnumberWhile the user is moving the vertex, from how far away should the vertex snap in order to arrange itself perpendicularly to another vertex? Default is 20.
vertexAddingboolean

Can the user add new vertices (by clicking a segment of the link)?

ValueDescription
falseThe user can not add new vertices.
trueAn invisible path is rendered above the link which creates vertices upon interaction with it.
{}See VertexAddingOptions
vertexMovingbooleanCan the user move vertices (by dragging them)? Default is true.
vertexRemovingbooleanCan the user remove vertices (by double clicking them)? Default is true.
stopPropagationbooleanShould be events stopped from propagating to the paper? Default is true.
handleClassmvc.ViewThe view for the vertex handle. By default it uses linkTools.Vertices.VertexHandle class.
scalenumberScale the vertices handles up or down on a 2D plane. The default is 1.

Example:

var verticesTool = new joint.linkTools.Vertices({
focusOpacity: 0.5,
redundancyRemoval: false,
snapRadius: 10,
vertexAdding: false,
});

VertexAddingOptions​

OptionTypeDescription
interactiveLinkNodestringA selector of an existing link node, e.g. "wrapper". When the node is interacted with, a vertex is created.

The default is true.

const verticesTool = new linkTools.Vertices({
// The link node referenced by the selector "outline"
// will create a vertex when interacted with.
vertexAdding: { interactiveLinkNode: 'outline' }
}),

Control​

The Control link tool is an abstract class which allows you to build tools to control the look or shape of a link by simply dragging a UI handle. It accepts a few additional arguments, which can be passed as an object to the link tool constructor:

selectorstring | nullThe link selector pointing to a link subnode, which the tool draws a frame around during dragging. If null provided, no frame will be shown.
paddingnumberThe padding between the area and the bounding box of the node designated by selector.
handleAttributesfunctionAn object with SVG attributes to be applied to the tool's handle.
scalenumberScale the button up or down on a 2D plane. The default is 1.
namespace Control {
interface Options extends dia.ToolView.Options {
selector?: string;
padding?: number;
handleAttributes?: Partial<attributes.NativeSVGAttributes>
}
}

abstract class Control extends dia.ToolView {
protected getPosition(view: dia.LinkView): dia.Point;
protected setPosition(view: dia.LinkView, coordinates: g.Point, evt: dia.Event): void;
protected resetPosition(view: dia.LinkView, evt: dia.Event): void;
}
getPosition(view: dia.LinkView): dia.Point;

The method should return the position of the handle based on a model value. The position is defined in the graph coordinate system.

setPosition(view: dia.LinkView, coordinates: g.Point, evt: dia.Event): void;

The method is executed each time the handle is moved. It's supposed to set the new model value derived from the current pointer coordinates (defined in the graph coordinate system)

resetPosition(view: dia.LinkView, evt: dia.Event): void;The method is executed when the handle is double-clicked. It's supposed to reset the model value back to a default.

See element Control tool for example usage.

RotateLabel​

The RotateLabel link tool allows you to rotate the link label by dragging a handle. It extends the Control tool and accepts additional arguments, which can be passed as an object to the link tool constructor:

labelIndexnumberThe index of the label in the labels array of the link model. Default is 0.
buttonColorstringThe color of the handle. Default is #333.
iconColorstringThe color of the icon. Default is #fff.
outlineColorstringThe color of the handle outline. Default is #333.

If the link has multiple labels, you can specify the index of the label you want to rotate using the labelIndex option. If the label with given index does not exist, the rendering of the tool will be posponed until the label is added.