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.
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 JsPlumb'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 { newInstance,
LabelOverlay,
StateMachineConnector,
EVENT_CLICK,
DotEndpoint,
AnchorLocations } from "@jsplumbtoolkit/browser-ui"
const toolkit = newInstance()
const surface = toolkit.render(someElement, {
"view": {
"nodes": {
"table": {
"templateId": "tmplTable"
},
"view": {
"templateId": "tmplView",
"events": {
EVENT_CLICK: (params:{node:Node}) => {
alert(\click on view \" + params.node.id);
}"
}
}
},
"edges": {
"common": {
"connector": StateMachineConnector.type,
"paintStyle": {
"lineWidth": 2,
"strokeStyle": "#CCC"
}
},
"1:1": {
"parent": "common",
"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": {
"column": {
"templateId": "tmplColumn",
"endpoint": {
"type": DotEndpoint.type,
"options": {
"radius": 7
}
},
"anchor": [
AnchorLocations.Left,
AnchorLocations.Right
],
"edgeType": "common"
}
}
}
});
Mapping types
An instance of the JsPlumbToolkit 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":{
template:`<div class="aNode">{{label}}</div>`
}
}
},
...
}
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, @jsplumbtoolkit/browser-ui
exports a constant DEFAULT
whose value is "default":
import { DEFAULT } from "@jsplumbtoolkit/browser-ui"
{
...
view:{
nodes:{
[DEFAULT]:{
template:`<div class="aNode">{{label}}</div>`
}
}
},
...
}
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:
import { newInstance,
EVENT_CLICK } from "@jsplumbtoolkit/browser-ui"
const toolkit = newInstance()
const surface = toolkit.render(someElement, {
"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 mappings for each node type in their own definitions.
Multiple parents
parent
may specify an array of definition ids:
import { newInstance,
ArrowOverlay } from "@jsplumbtoolkit/browser-ui"
const toolkit = newInstance()
const surface = toolkit.render(someElement, {
"view": {
"edges": {
"sourceArrow": {
"overlays": [
{
"type": ArrowOverlay.type,
"options": {
"location": 0,
"direction": -1
}
}
]
},
"targetArrow": {
"overlays": [
{
"type": ArrowOverlay.type,
"options": {
"location": 1
}
}
]
},
"bothArrows": {
"parent": [
"sourceArrow",
"targetArrow"
]
}
}
}
});
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:
You can map various events to edges inside your view, via the events
parameter listed above. The list of bindable events is:
export type BindableEvent = "click" | "dblclick" |
"mouseover" |
"mouseout" |
"mousedown" |
"mouseup" |
"tap" |
"dbltap" |
"contextmenu"
{
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 JsPlumb 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:
Name | Type | Description |
---|---|---|
allowLoopback? | boolean | 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 | Whether or not to allow edges from a port back to the vertex it belongs to. Defaults to true. |
anchorPositionFinder? | 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 array of anchor positions to use. |
defaultSize? | Size | Optional default size to use for the vertex. This is not used to set the size in the DOM for a vertex - it is used
to insert width and height values into the backing data for any vertex of this type that does not have them set. |
events? | ViewEventOptions | Optional map of event bindings. |
maxConnections? | number | Maximum number of connections this vertex supports. Default is 1. A value of -1 means no limit. |
mergeStrategy? | string | 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' . |
parameters? | Record | A map of parameters that the template engine will merge with the backing data when rendering the vertex. |
parent? | 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. | |
template? | string | 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 | 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.
Name | Type | Description |
---|---|---|
anchor? | AnchorSpec | Spec for the anchor to use for both source and target for edges of this type. |
anchors? | [source, target] anchor specs edges of this type. | |
avoidVertices? | boolean | If true, the edge will be routed to avoid any vertices. You must be using the Straight connector for this to work. Note also that if your edge has any user edits, or was loaded with a path specified, the edge will not be routed to avoid vertices. |
connector? | ConnectorSpec | Name/definition of the connector to use. If you omit this, the default connector will be used. |
cssClass? | string | CSS class to add to edges of the type in the UI |
deleteButton? | Optional delete button. | |
deleteButtonClass? | string | Optional class name to set on the delete button. Defaults to "jtk-edge-delete". |
deleteButtonLocation? | Location for an edge's delete button, if applicable. Defaults to 0.1. You can supply an array of locations if you want multiple buttons. | |
deleteConfirm? | EdgeDeleteConfirmationFunction | An optional function to invoke if the user presses the delete button on some edge. When this is present and the user clicks an edge delete button, instead of just deleting the edge, this function is invoked. It is passed the edge that is a candidate for deletion, and a function which you must invoke if you wish to proceed. |
detachable? | boolean | Whether or not edges of this type should be detachable with the mouse. Defaults to true. |
endpoint? | EndpointSpec | Optional spec to use for both the source and target endpoints for edges of this type. |
endpointHoverStyle? | EndpointStyle | Optional paint style to use for hover on both the source and target endpoints for edges of this type. |
endpointHoverStyles? | Optional paint style to use for hove on the [source, target] endpoints for edges of this type. | |
endpoints? | Optional specs for the [source, target] endpoints for edges of this type. | |
endpointStyle? | EndpointStyle | Optional paint style to use for both the source and target endpoints for edges of this type. |
endpointStyles? | Optional paint styles to use for the [source, target] endpoints for edges of this type. | |
events? | ViewEventOptions | Optional map of event bindings. |
hoverPaintStyle? | PaintStyle | Paint style to use for the edge when the pointer is hovering over it. |
label? | string | 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 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 location for the label. If not provided this defaults to 0.5, but the label location can be controlled via the
labelLocationAttribute . |
labelLocationAttribute? | string | 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. |
mergeStrategy? | string | 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' . |
outlineWidth? | number | Optional width of the edge's outline. Defaults to 0. |
overlays? | Array<OverlaySpec> | Array of overlays to add to edges of this type. |
paintStyle? | PaintStyle | Paint style to use for the edge. |
parent? | 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. | |
reattach? | boolean | Whether or not when a user detaches a edge of this type it should be automatically reattached. Defaults to false. |
useHTMLLabel? | boolean | By default, an SVG element will be used for an edge's label overlay. This is good because the label can be exported as part of an SVG export of your canvas. If you wish to use an HTML element instead, set this flag. |
Edge labels
You can use a shortcut syntax to display a label on each edge. See the label
option listed above. With this property set, JsPlumb will 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, JsPlumb 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, JsPlumb 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 JsPlumb 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. Port mappings are defined by the
ViewPortOptions
interface:
Name | Type | Description |
---|---|---|
allowLoopback? | boolean | 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 | Whether or not to allow edges from a port back to the vertex it belongs to. Defaults to true. |
anchor? | AnchorSpec | Spec for anchors connected to this port |
anchorOffsetX? | number | 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 | 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 | The orientation in the x axis for connections attached to an anchor created for this port. |
anchorOrientationY? | number | The orientation in the y axis for connections attached to an anchor created for this port. |
anchorPositionFinder? | 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 array of anchor positions to use. |
anchorX? | number | 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 | 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 | Type of edges generated by this port. |
endpoint? | EndpointSpec | If isEndpoint is set to true, you can provide a spec for the endpoint with this parameter. |
events? | ViewEventOptions | Optional map of event bindings. |
hoverPaintStyle? | PaintStyle | If isEndpoint is set to true, you can provide a spec for the endpoint's hover paint style with this parameter. |
isEndpoint? | boolean | 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 | Whether or not the port can act as a source for dragged connections. Defaults to false. |
isTarget? | boolean | Whether or not the port can act as a target for dragged connections. Defaults to false. |
maxConnections? | number | Maximum number of connections this vertex supports. Default is 1. A value of -1 means no limit. |
mergeStrategy? | string | 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' . |
paintStyle? | PaintStyle | If isEndpoint is set to true, you can provide a spec for the endpoint's paint style with this parameter. |
parameters? | Record | A map of parameters that the template engine will merge with the backing data when rendering the vertex. |
parent? | 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. | |
template? | string | 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 | 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. |
uniqueEndpoint? | boolean | 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. |
Groups
For a full discussion on Groups, including how to map them inside views, take a look at this page.
The main thing you'll want to map in a group definition is the template to use to render a group of that type. You can do this with either the templateId
property, which identifies a template by its ID that you are expecting JsPlumb to be able to resolve from the DOM, or with the template
property, where you provide the template inline.
Entries in the groups
section are expected to conform to the ViewGroupOptions
interface:
Name | Type | Description |
---|---|---|
allowLoopback? | boolean | 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 . |
allowShrinkFromOrigin? | boolean | When autoShrink or autoSize is set to true, this is also implicitly true, meaning that a group can be shrunk from its left/top edge. Set this to
default if you do not want that behaviour. |
allowVertexLoopback? | boolean | Whether or not to allow edges from a port back to the vertex it belongs to. Defaults to true. |
anchor? | AnchorSpec | Spec for the anchor to use for connections to children of the group when they are transferred to the group in its collapsed state. |
anchorPositionFinder? | 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 array of anchor positions to use. |
autoGrow? | boolean | Defaults to false, meaning that the group will not be resized if an item addition/removal or drag causes the bounds of the child members to change and the new size is greater than the previous size. |
autoShrink? | boolean | False by default. If true indicates that if a child member is dragged/added/removed and the group's size is recalculated to be smaller than
the previous size, the new size should be applied. From 6.10.0 this also works if the group needs to shrink from its left and/or top edge. If you don't
want that behaviour, set allowShrinkFromOrigin to false. |
autoSize? | boolean | False by default. From version 6.10.0 onwards this flag switches on both autoShrink and autoGrow and also enables support for shrinking a group from
its left or top edge, a feature that was not available in previous versions. If you're on 6.10.0+ and you want to setup your UI to be how it used to be with
just this flag set, also set autoShrink to false. If you previously had autoShrink set to true but you don't like the shrink from left/top functionality,
set allowShrinkFromOrigin to false. |
constrain? | boolean | False by default - nodes/groups may be dragged outside of the bounds of the group. When you do drag a node/group outside of the bounds of its parent, what happens next depends on the other flags you have set and where you have dropped it. orphan:true , for instance, will cause the node/group to be removed from its parent group. revert will reinstate the node/group's position inside its parent, unless it was dropped on another group. |
defaultSize? | Size | Optional default size to use for the vertex. This is not used to set the size in the DOM for a vertex - it is used
to insert width and height values into the backing data for any vertex of this type that does not have them set. |
dropOverride? | boolean | False by default. If true, Nodes dropped onto other Groups first have any rules established by this Group applied. For instance, if the Groups stated prune:true , then the Node would be removed from the dataset rather than be dropped onto another Group. |
droppable? | boolean | True by default - indicates that nodes/groups may be dropped onto the group, either from some other group or from the main canvas. |
elastic? | boolean | Similar to autoGrow, but with a couple of differences: - elements cannot be dragged out of the group, unless the user holds down SHIFT while dragging - shows a visual prompt when a group will be resized as a result of |
elementsDraggable? | boolean | True by default - indicates that child members may be dragged around inside the group. |
endpoint? | EndpointSpec | Spec for the endpoint to use for connections to children of the group when they are transferred to the group in its collapsed state. |
events? | ViewEventOptions | Optional map of event bindings. |
ghost? | boolean | Whether or not to show a 'ghost' element when an element inside the group is dragged to the point that it extends outside the bounds of the group. The original element remains inside the group. Defaults to false. |
layout? | Options for the group's layout. | |
maxConnections? | number | Maximum number of connections this vertex supports. Default is 1. A value of -1 means no limit. |
maxSize? | Size | Maximum size the group can grow to. If not specified the group can grow to an arbitrary size. Note that this behaviour can also be enforced via CSS. |
mergeStrategy? | string | 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' . |
minSize? | Size | Minimum size the group can be. This is only used when |
orphan? | boolean | False by default. If true, nodes/groups dropped outside of the group (and not dropped onto another group) are removed from the group (but remain in the dataset). When you set this to true , revert is automatically forced to false . |
padding? | number | Optional padding to set inside a group when computing an auto size. |
parameters? | Record | A map of parameters that the template engine will merge with the backing data when rendering the vertex. |
parent? | 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. | |
prune? | boolean | False by default. If true, Nodes dropped outside of the Group (and not dropped onto another Group) are removed from the dataset (not just the Group...the entire dataset). |
revert? | boolean | True by default - a node/group dragged outside of its parent group will, unless dropped on another group, revert back to its position inside the group. |
template? | string | 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 | 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. |
Preconfigured Parameters
The information in this section applies only to Vanilla JsPlumb.
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"
}
}
}
}
Preconfigured parameters are known to break 2-way data binding when using JsPlumb 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, Svelte and React - JsPlumb 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.
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.
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.