Skip to main content

Views

Views are used to define the visual appearance of the various artifacts (which template to use for nodes/groups/ports, CSS classes, connector types and anchors for edges, etc) and event registration. If you want to read about defining connectivity rules, see the Data Model documentation.

When using vanilla Toolkit (no library integrations), views are provided as an argument to the render method of an instance of the Toolkit. When using a library integration views are specified separately from render parameters.

The general form of a view is that it contains a section for nodes, edges, ports and groups, the keys of which are types, and the values are sets of configuration. Not every section needs to appear in a view - a view can, in fact, be entirely empty or not present at all, but views are the glue that holds the Toolkit's UI layer together.

Example

Just to jump in quickly, this example is an edited View from the Schema Builder example application.

In this view we have two node types, each of which declares the ID of a template to use to render it, and the "view" node type also declares a click handler. In the edges section we see three edge types, with the "common" type acting a base type for the others. The ports section declares a single type - "column" - which indicates the ID of a template to use to render columns, the endpoint/anchor definitions, and also what "type" to set on edges dragged from the port. Note that there is no groups section in this view; we don't need it for this app.

Below, we'll go through the options for each section in detail.


import { AnchorLocations, LabelOverlay, DotEndpoint, EVENT_CLICK, StateMachineConnector } from "@jsplumbtoolkit/browser-ui"

toolkit.render(someTargetElement, {
view:{
// we have two node types - 'table' and 'view'.
nodes:{
"table":{
// we use 'tmplTable' to render tables
templateId:"tmplTable"
},
"view":{
// and 'tmplView' to render views
templateId:"tmplView",
events:{
// when you click a view Node, we alert its id.
[EVENT_CLICK]:(params:{node:Node}) => {
alert("click on view " + params.node.id);
}
}
}
},
edges:{
// common appearance of all edges
"common":{
connector:StateMachineConnector.type,
paintStyle:{ lineWidth:2, strokeStyle:"#CCC" }
},
// a 1:1 relationship
"1:1":{
parent:"common", // declared 'common' as its parent.
overlays:[
{ type:LabelOverlay.type, options:{ label:"1", location:0.1 } },
{ type:LabelOverlay.type, options:{ label:"1", location:0.9 } }
]
},
"1:N":{
parent:"common",
overlays:[
{ type:LabelOverlay.type, options:{ label:"1", location:0.1 }},
{ type:LabelOverlay.type, options:{ label:"N", location:0.9 }}
]
}
},
ports:{
// a table has an arbitrary number of columns; it is a table's columns that actually connect to other tables, not a table itself.
"column":{
// use 'tmplColumn' to render a Port of type 'column'
templateId:"tmplColumn",
// the appearance of the endpoint on a column
endpoint:{type:DotEndpoint.type, options:{ radius:7 } },
// anchor locations on a column
anchor:[ AnchorLocations.Left, AnchorLocations.Right ],
// the type of edge that will be created from this port by default when the user drags a connection
edgeType:"common"
}
}
}
})

Mapping types

An instance of the Toolkit has the concept of a typeFunction - a function that, when given the data corresponding to some node, port, edge or group, returns the object's type (as a string). The type returned by this function is what is used as the key into a view (for instance, the "table" and "view" node types above, or the "1:N" edge type etc).

Default Types

For each of nodes, groups, ports and edges, you can provide a default definition, using the key "default":

{
...
view:{
nodes:{
"default":{
templateId:"tmplNode"
}
}
},
...
}

This definition will be used in two circumstances:

  • no type was derived for some object by the current typeFunction
  • a type was derived but there is no entry in the view for that type

For convenience, @jsplumb/common exports a constant DEFAULT whose value is "default":


import { DEFAULT } from "@jsplumbtoolkit/browser-ui"

{
...
view:{
nodes:{
[DEFAULT]:{
templateId:"tmplNode"
}
}
},
...
}

Default Edge Type

If you do not specify an edgeType parameter on a port definition, the type will be set to default.


Definition Inheritance

Any node, port, edge or group definition can declare a parent. The resulting definition consists of the parent's entries, with the child's entries merged on top. An example:

{
...
view:{
nodes:{
"common":{
events:{
[EVENT_CLICK]:(params:{node:Node}) => {
console.log("Click on node", params.node);
}
}
},
bigNode:{
parent:"common",
templateId:"tmplBigNode"
},
smallNode:{
parent:"common",
templateId:"tmplSmallNode"
}
}
},
...
}

Here, we have defined a common click handler on the parent definition, and then defined templates for each Node type in their own definitions.

As of 5.11.0, parent may specify an array of definition ids:

{
...
view:{
nodes:{
"sourceArrow":{
overlays:[ { type:"Arrow", options:{location:0, direction:-1}}]
},
targetArrow:{
overlays:[ { type:"Arrow", options:{location:1}}]
},
bothArrows:{
parent:["sourceArrow", "targetArrow"]
}
}
},
...
}

Common properties

Each entry type in the view is represented by the Toolkit as an interface, and each of these interfaces extends one common interface - ViewOptionsCommon. The available parameters in the common interface are:

Home > @jsplumbtoolkit/browser-ui > ViewOptionsCommon

ViewOptionsCommon interface

Common options for edge/node/group/port definitions in a view.

Signature:

export interface ViewOptionsCommon 

Properties

PropertyModifiersTypeDescription
events?ViewEventOptions(Optional) Optional map of event bindings.
mergeStrategy?string(Optional) When merging a type description into its parent(s), values in the child for connector, anchor and anchors will always overwrite any such values in the parent. But other values, such as overlays, will be merged with their parent's entry for that key. You can force a child's type to override _every_ corresponding value in its parent by setting mergeStrategy:'override'.
parent?string | Array<string>(Optional) Optional ID of one or more edge definitions to include in this definition. The child definition is merged on top of the parent definition(s). Circular references are not allowed and will throw an error.

Render events

Each type of object in the View supports declarative registration of events, through the inclusion of an events member in the appropriate definition. The list of supported events is as follows:

  • tap
  • dbltap
  • click
  • dblclick
  • mousedown
  • mouseup
  • mouseout
  • mouseover
  • contextmenu
view:{
nodes:{
someNodeType:{
events:{
click:(params) => {
// params.toolkit is the Toolkit instance
// params.renderer is the Surface widget
// params.e is the original mouse event
// params.node is the Toolkit Node
// params.el is the element from the DOM representing the Node
}
}
}
},
edges:{
someEdgeType:{
events:{
mouseover:(params) => {
// params.toolkit is the Toolkit instance
// params.renderer is the Surface widget
// params.e is the original mouse event
// params.edge is the Toolkit Edge
// params.connection is a jsPlumb Connection object.
console.dir(params.edge, params.connection);
}
}
}
},
ports:{
somePortType:{
events:{
mousedown:(params) => {
// params.toolkit is the Toolkit instance
// params.renderer is the Surface widget
// params.e is the original mouse event
// params.port is the Toolkit Port
// params.endpoint is a jsPlumb Endpoint object
console.dir(params.port, params.endpoint);
}
}
}
},
groups:{
someGroupType:{
events:{
click:(params) => {
// params.toolkit is the Toolkit instance
// params.renderer is the Surface widget
// params.e is the original mouse event
// params.group is the Toolkit group
// params.el is the element from the DOM representing the group
}
}
}
}
}

Nodes

The main thing you'll want to map in a node definition is the template to use to render a node of that type. You can do this with either the templateId property, which identifies a template by its ID that you are expecting the Toolkit to be able to resolve from the DOM, or with the template property, where you provide the template inline.

Entries in the nodes section are expected to conform to the ViewNodeOptions interface, which is itself inherited from ViewNodeOrPortOptions and in fact currently adds no extra keys. So here we show the properties available on ViewNodeOrPortOptions

Home > @jsplumbtoolkit/browser-ui > ViewNodeOrPortOptions

ViewNodeOrPortOptions interface

Base view definition options for nodes and ports (and groups, since they extend nodes)

Signature:

export interface ViewNodeOrPortOptions extends ViewOptionsCommon 

Extends: ViewOptionsCommon

Properties

PropertyModifiersTypeDescription
allowLoopback?boolean(Optional) Whether or not to allow edges from this vertex back to itself. Defaults to true. This flag will not prevent an edge from a port back to the node/group to which it belongs - for that, see allowVertexLoopback.
allowVertexLoopback?boolean(Optional) Whether or not to allow edges from a port back to the vertex it belongs to. Defaults to true.
anchorPositionFinder?(el: Element, pos: PointXY, vertex: Node | Group, def: ViewNodeOptions, evt: Event) => ArrayAnchorSpec | null(Optional) Optional function to call on connection drop, to determine the location for the target anchor for the new connection. Returning null from this indicates no preference, and the Toolkit will use its own computed value. Note that the return value from this method is ArrayAnchorSpec, meaning an array in the format [ x, y, orientationX, orientationY, offsetX, offsetY ]. Note also that offsetX and offsetY are optional, and will be defaulted to 0.
anchorPositions?Array<ObjectAnchorSpec>(Optional) Optional array of anchor positions to use.
maxConnections?number(Optional) Maximum number of connections this vertex supports. Default is 1. A value of -1 means no limit.
parameters?Record<string, any>(Optional) A map of parameters that the template engine will merge with the backing data when rendering the vertex.
template?string(Optional) Template to use for a vertex of this type. This is only for 'vanilla' Toolkit: if you are using an integration such as React/Angular/Vue/Svelte, you will not need to provide this. If you provide this and also templateId, this will take precedence.
templateId?string(Optional) ID of the template to use for a vertex of this type. This is only for 'vanilla' Toolkit: if you are using an integration such as React/Angular/Vue, you will not need to provide this. This parameter is distinct from template in that when you provide templateId you are expecting the Toolkit to resolve the template for you, either from a templates block in a render call, or by looking for a script element in the DOM with the appropriate ID. If you provide this and also template, template will take precedence.

Edges

Edges in a view conform to the ViewEdgeOptions interface, which offers an extensive means of configuring the appearance and behaviour of your edges.

Home > @jsplumbtoolkit/browser-ui > ViewEdgeOptions

ViewEdgeOptions interface

The mapping for the definition of an edge inside a view.

Signature:

export interface ViewEdgeOptions extends ViewOptionsCommon 

Extends: ViewOptionsCommon

Properties

PropertyModifiersTypeDescription
anchor?AnchorSpec(Optional) Spec for the anchor to use for both source and target for edges of this type.
anchors?[AnchorSpec, AnchorSpec](Optional) [source, target] anchor specs edges of this type.
connector?ConnectorSpec(Optional) Name/definition of the connector to use. If you omit this, the default connector will be used.
cssClass?string(Optional) CSS class to add to edges of the type in the UI
detachable?boolean(Optional) Whether or not edges of this type should be detachable with the mouse. Defaults to true.
endpoint?EndpointSpec(Optional) Optional spec to use for both the source and target endpoints for edges of this type.
endpointHoverStyle?EndpointStyle(Optional) Optional paint style to use for hover on both the source and target endpoints for edges of this type.
endpointHoverStyles?[EndpointStyle, EndpointStyle](Optional) Optional paint style to use for hove on the [source, target] endpoints for edges of this type.
endpoints?[EndpointSpec, EndpointSpec](Optional) Optional specs for the [source, target] endpoints for edges of this type.
endpointStyle?EndpointStyle(Optional) Optional paint style to use for both the source and target endpoints for edges of this type.
endpointStyles?[EndpointStyle, EndpointStyle](Optional) Optional paint styles to use for the [source, target] endpoints for edges of this type.
hoverPaintStyle?PaintStyle(Optional) Paint style to use for the edge when the pointer is hovering over it.
label?string(Optional) Optional label to use for the edge. If this is set, a label overlay will be created and the value of label will be used as the overlay's label. This value can be parameterised, in order to extract a value from the edge's backing data, eg. if you set label:"{{name}}" then the Toolkit would attempt to extract a property with key name from the edge's backing data, and use that property's value as the label.
labelClass?string(Optional) Optional css class to set on the label overlay created if label is set. This is a static string and does not support parameterisation like label does.
labelLocation?number(Optional) Optional location for the label. If not provided this defaults to 0.5, but the label location can be controlled via the labelLocationAttribute.
labelLocationAttribute?string(Optional) This defaults to labelLocation, and indicates the name of a property whose value can be expected to hold the location at which the label overlay should be located. The default value for this is labelLocation, but the key here is that the Toolkit looks in the edge data for labelLocation, so the location is dynamic, and can be changed by updating labelLocation. This parameter allows you to change the name of the property that the Toolkit will look for in the edge data.
outlineWidth?number(Optional) Optional width of the edge's outline. Defaults to 0.
overlays?Array<OverlaySpec>(Optional) Array of overlays to add to edges of this type.
paintStyle?PaintStyle(Optional) Paint style to use for the edge.
reattach?boolean(Optional) Whether or not when a user detaches a edge of this type it should be automatically reattached. Defaults to false.
useHTMLLabel?boolean(Optional)

Edge labels

Since 5.11.0 it has been possible to use a shortcut syntax to display a label on each edge. See the label option listed above? You can use this have the Toolkit automatically create a label overlay for some edge type:

edges:{
"someType":{
label:"FOO"
}
}

Here, we've said that all edges of type "someType" will have a label with the text "FOO". We can also use dynamic values:

edges:{
"someType":{
label:"{{labelKey}}"
}
}

In this example, the Toolkit will extract the value of the property labelKey from each edge's backing data, and set that as the text in the label overlay.

Edge label location

By default, a label overlay created with this mechanism will be located at 0.5, that is halfway along the length of the edge. When you provide label in an edge definition, the Toolkit also registers an observer for the property with key labelLocation, and if a value for this key is present, the location of the label will be placed accordingly. So with this edge data and the above label:"{{labelKey}}" mapping:

{
labelKey:"i am the label",
labelLocation:0.2
}

You'd get a label overlay with "i am the label" positioned at 0.2.

You can change the name of the attribute the Toolkit uses to determine label location if you wish:

edges:{
"someType":{
label:"{{labelKey}}",
labelLocationAttribute:"whereTheLabelShouldBe"
}
}

We'd use this edge data in that case:

{
labelKey:"i am the label",
whereTheLabelShouldBe:0.2
}

Ports

Ports are vertices in the data model, and can be rendered either as a DOM element, or as an endpoint. Above, we saw the ViewNodeOrPortOptions interface, which defines common properties between nodes and ports. We'll repeat it here to save you scrolling:

Home > @jsplumbtoolkit/browser-ui > ViewNodeOrPortOptions

ViewNodeOrPortOptions interface

Base view definition options for nodes and ports (and groups, since they extend nodes)

Signature:

export interface ViewNodeOrPortOptions extends ViewOptionsCommon 

Extends: ViewOptionsCommon

Properties

PropertyModifiersTypeDescription
allowLoopback?boolean(Optional) Whether or not to allow edges from this vertex back to itself. Defaults to true. This flag will not prevent an edge from a port back to the node/group to which it belongs - for that, see allowVertexLoopback.
allowVertexLoopback?boolean(Optional) Whether or not to allow edges from a port back to the vertex it belongs to. Defaults to true.
anchorPositionFinder?(el: Element, pos: PointXY, vertex: Node | Group, def: ViewNodeOptions, evt: Event) => ArrayAnchorSpec | null(Optional) Optional function to call on connection drop, to determine the location for the target anchor for the new connection. Returning null from this indicates no preference, and the Toolkit will use its own computed value. Note that the return value from this method is ArrayAnchorSpec, meaning an array in the format [ x, y, orientationX, orientationY, offsetX, offsetY ]. Note also that offsetX and offsetY are optional, and will be defaulted to 0.
anchorPositions?Array<ObjectAnchorSpec>(Optional) Optional array of anchor positions to use.
maxConnections?number(Optional) Maximum number of connections this vertex supports. Default is 1. A value of -1 means no limit.
parameters?Record<string, any>(Optional) A map of parameters that the template engine will merge with the backing data when rendering the vertex.
template?string(Optional) Template to use for a vertex of this type. This is only for 'vanilla' Toolkit: if you are using an integration such as React/Angular/Vue/Svelte, you will not need to provide this. If you provide this and also templateId, this will take precedence.
templateId?string(Optional) ID of the template to use for a vertex of this type. This is only for 'vanilla' Toolkit: if you are using an integration such as React/Angular/Vue, you will not need to provide this. This parameter is distinct from template in that when you provide templateId you are expecting the Toolkit to resolve the template for you, either from a templates block in a render call, or by looking for a script element in the DOM with the appropriate ID. If you provide this and also template, template will take precedence.

These are the options that are also available on a port definition:

Home > @jsplumbtoolkit/browser-ui > ViewPortOptions

ViewPortOptions interface

Definition of a port inside a view.

Signature:

export interface ViewPortOptions extends ViewNodeOrPortOptions 

Extends: ViewNodeOrPortOptions

Properties

PropertyModifiersTypeDescription
anchor?AnchorSpec(Optional) Spec for anchors connected to this port
anchorOffsetX?number(Optional) Offset, in pixels, to apply to the position in the x axis after the anchorX value has been used to compute its default position.
anchorOffsetY?number(Optional) Offset, in pixels, to apply to the position in the y axis after the anchorY value has been used to compute its default position.
anchorOrientationX?number(Optional) The orientation in the x axis for connections attached to an anchor created for this port.
anchorOrientationY?number(Optional) The orientation in the y axis for connections attached to an anchor created for this port.
anchorX?number(Optional) The x location of any anchors created for this port. Allows you to specify where, in proportional values, the anchor should be located in the x axis. For a full discussion of how to use this (and the other anchor properties in this interface), see the documentation for anchors.
anchorY?number(Optional) The y location of any anchors created for this port. Allows you to specify where, in proportional values, the anchor should be located in the y axis.
edgeType?string(Optional) Type of edges generated by this port.
endpoint?EndpointSpec(Optional) If isEndpoint is set to true, you can provide a spec for the endpoint with this parameter.
hoverPaintStyle?PaintStyle(Optional) If isEndpoint is set to true, you can provide a spec for the endpoint's hover paint style with this parameter.
isEndpoint?boolean(Optional) If true, the port is rendered as an endpoint. By default this is false (meaning the port is represented by some DOM element that you have rendered).
isSource?boolean(Optional) Whether or not the port can act as a source for dragged connections. Defaults to false.
isTarget?boolean(Optional) Whether or not the port can act as a target for dragged connections. Defaults to false.
paintStyle?PaintStyle(Optional) If isEndpoint is set to true, you can provide a spec for the endpoint's paint style with this parameter.
uniqueEndpoint?boolean(Optional) Normally, each time a new connection is established a port on which isEndpoint is set to true, a new endpoint is created for that connection. Setting this flag will cause the Toolkit to only ever create a single endpoint for the port, to which all connections should be attached. Note that you may wish to consider the maxConnections parameter if you use this, as by default the endpoint will be created with a limit of 1 connection.

As with nodes, ports can be associated with a template for rendering. They do no have to be - in some cases, you will want to use an endpoint to represent a port, and in others you'll want to use a DOM element. If you're using DOM elements and your application supports the dynamic addition of new ports - as in the case of the Schema Builder when the user adds a new column to a table - then you need to provide the Toolkit with a separate template to use to render the port (as opposed to rendering the ports inside of each node's template).


Groups

For a full discussion on Groups, including how to map them inside Views, take a look at this page.


Preconfigured Parameters

You may have a template that you'd like to reuse for a collection of nodes, with slight variations between each. Consider this example:

<script type="jtk" id="tmplRectangle-svg">
<svg:svg style="position:absolute;left:0;top:0;" version="1.1" xmlns="http://www.w3.org/1999/xhtml">
<svg:rect width="{{width}}" height="{{height}}" x="{{strokeWidth}}" y="{{strokeWidth}}" fill="{{fill}}" stroke="{{stroke}}" stroke-width="{{strokeWidth}}"/>
</svg:svg>
</script>

This template draws SVG rectangles, of any given size, with arbitrary fill and stroke, and possibly rotated. Let's say we're creating an application in which there are two types of rectangle shapes: big red ones, and little yellow ones. In our View we can define custom parameters for each of these node types, which will be mixed in with the node's data when it comes time to render:

view:{
nodes:{
"bigRed":{
templateId:"tmplRectangle",
parameters:{
width:250,
height:250,
fill:"red"
}
},
"smallYellow":{
templateId:"tmplRectangle",
parameters:{
width:50,
height:50,
fill:"yellow"
}
}
}
}
note

Preconfigured parameters are known to break 2-way data binding when using the Toolkit with AngularJS, because the data object passed to the template is a copy of the original. To switch off preconfigured parameters, set enhancedview:false in your render call. With the other library integrations - Angular, Vue 2/3, Svelte and React - the Toolkit takes care of setting this flag appropriately.

Preconfigured Parameters & Inheritance

Preconfigured parameters are merged when one definition inherits from another, but only to the first level. Consider this arrangement:

view:{
nodes:{
"base":{
templateId:"tmplRectangle",
parameters:{
lineWidth:2,
foo:{
bar:"baz"
}
}
},
"bigRed":{
parent:"base",
parameters:{
width:250,
height:250,
fill:"red",
foo:{
qux:"FOO"
}
}
},
"smallYellow":{
parent:"base",
parameters:{
width:50,
height:50,
fill:"yellow"
}
}
}
}

Note the foo parameter is declared in all three definitions. After merging, the two concrete node definitions have these values:

"bigRed":{
parent:"base",
parameters:{
width:250,
height:250,
fill:"red",
foo:{
qux:"baz"
}
}
}

"smallYellow":{
parent:"base",
parameters:{
width:50,
height:50,
fill:"yellow",
foo:{
bar:"baz"
}
}
}

So the foo entry in bigRed would completely overwrite the foo entry from base; the two are not merged together. smallYellow does not have foo entry and therefore inherits it from base.

caution

Preconfigured parameters operate at the view level only: they are not written into your data model. So you cannot use this mechanism to provide parameters that you will subsequently update (such as the w/h parameters that the Flowchart Builder demo uses: if provided via the preconfigured parameters mechanism the UI would initially render correctly, but if the w/h values were updated, the template would not re-render. In the Flowchart Builder, the solution is to provide the w/h in the data model).

Switching off Preconfigured Parameters

As mentioned above, there are some cases in which you cannot use preconfigured parameters. One such known case is when you are using AngularJS and you're taking advantage of the two-way data binding provided by its template engine. Preconfigured parameters (and function parameters, discussed below), cause a copy of the original data to be created, which then breaks AngularJS's two-way binding. A copy is created because the only other option is to copy the preconfigured parameters into the original data, which is almost certainly not what you want, given that they are a view concern.

To switch off preconfigured parameters and function parameters, set the enhancedView flag on your render call to false:

_toolkit.render({
container:"someElement",
view:{
nodes:{
"circleNodeDef" : {
templateId:"tmplCircle",
parameters:{
lineWidth:5,
radius:10,
fill:"black"
}
}
}
},
enhancedView:false
});

Function Parameters

By default you can provide values in definitions as functions. These will be given the backing data for the object being rendered. An example definition:

_toolkit.render(document.getElementById("someElement"), {
view:{
nodes:{
"circleNodeDef" : {
templateId:"tmplCircle",
parameters:{
lineWidth:5,
radius:10,
fill:"black",
stroke:function(data) { return data.error ? "red" : "green"; }
}
}
}
}
});

If we were to make this call:

var node = _toolkit.addNode({
type:"circleNodeDef",
error:true
});

we'd end up with a circle that has a red outline. Otherwise we'd get a green outline.

note

Function parameters are known to break 2-way data binding when using the Toolkit with AngularJS, because the data object passed to the template is a copy of the original. To switch off function parameters, set enhancedView:false in your render call.

Switching off Function Parameters

See Switching off Preconfigured Parameters.


View Options

The specific interface for a view now is SurfaceViewOptions

Home > @jsplumbtoolkit/browser-ui > SurfaceViewOptions

SurfaceViewOptions interface

Signature:

export interface SurfaceViewOptions 

Properties

PropertyModifiersTypeDescription
edges?ViewOptionsEntry<ViewEdgeOptions>(Optional)
groups?ViewOptionsEntry<ViewGroupOptions>(Optional)
nodes?ViewOptionsEntry<ViewNodeOptions>(Optional)
ports?ViewOptionsEntry<ViewPortOptions>(Optional)