Skip to main content

UI States

A common use case is the requirement to temporarily paint a set of nodes/groups/ports and/or edges with some set of styles. The surface supports this through the concept of UI States. Prior to version 5.5.0 support for UI states was provided by the Surface component, but from 5.5.0 onwards UI states are now packaged in a separate package - @jsplumbtoolkit/browser-ui-plugin-ui-states.

First, an example. This is a snippet from the view parameter passed to a render call:

toolkitInstance.render(someElement, {
view:{

... other view content...

"states":{
"mintyGreenState":{
"default":{
cssClass:"mintyGreen",
paintStyle:{ "strokeStyle":"#00FF00" },
endpointStyle: { fillStyle:"#00EE00" }
}
}
}
},
plugins:["ui-states"], // <-------- not required prior to version 5.5.0.

});

Here we have declared a state called mintyGreenState. When this state is active, all nodes of type default to which it applies will have a CSS class of mintyGreen added, and all edges of type default will be painted with a stroke style of #00FF00 (for the eagle-eyed, not quite minty green, it's true). All ports - which are represented via endpoints - will have a fill style of #00EE00.

The states themselves are listed inside the view on a render call, but note also the plugins parameter in the code snippet above: from 5.5.0 onwards, UI states are handled by a plugin from the @jsplumbtoolkit/browser-ui-plugin-ui-states package. If you're using Typescript or ES6 you can also strongly type this declaration:

import { UIStatesPlugin } from "@jsplumbtoolkit/browser-ui-plugin-ui-states"

toolkitInstance.render(someElement, {

view:{
...,
},
plugins:[ UIStatesPlugin.type ]

Note also that edges and ports will be assigned the CSS class of mintyGreen. So you need to ensure that any CSS rules related to UI states are specific enough that you do not accidentally apply node/group styles to a connection.

caution

When you call updateEdge, updateNode or updateGroup on a Toolkit instance, any edge, node or group states that are active for the given object will be cancelled and it will revert to its default state (albeit with the new data you provided).


Applying UI States

You can apply a state to any of the following:

note

From version 5.5.0 onwards states are manipulated by invoking methods on the UI states plugin, not by invoking methods on the Surface. The code snippets for 5.5.0 below include a reference to a plugin variable, which is retrieved from the Surface.

If you're using Javascript, you can retrieve the plugin with this call:

var plugin = surface.getPlugin("ui-states")

If you're using Typescript, you can use this call instead:

import { UiStatesPlugin } from "@jsplumbtoolkit/browser-ui-plugin-ui-states"

const plugin = surface.getPlugin<UiStatesPlugin>(UiStatesPlugin.type)

Applying state to the entire dataset

// < 5.5.0
surface.activateState("mintyGreenState") // in the absence of a second argument, the state is applied to the entire dataset.

// 5.5.0 +
plugin.activateState("mintyGreenState") // in the absence of a second argument, the state is applied to the entire dataset.

Applying state to a Toolkit's current selection

// < 5.5.0
surface.activateState("mintyGreenState", toolkit.getSelection())
// 5.5.0 +
plugin.activateState("mintyGreenState", toolkit.getSelection())

Applying state to an ad-hoc selection

const selection = toolkit.select(["node1", "node2"])
// < 5.5.0
surface.activateState("mintyGreenState", selection)
// 5.5.0 +
plugin.activateState("mintyGreenState", selection)

Applying state to a path

const path = toolkit.getPath({source:"node1", target:"node2"})
// < 5.5.0
surface.activateState("mintyGreenState", path)
// 5.5.0 +
plugin.activateState("mintyGreenState", path)

Methods available

In versions prior to 5.5.0 these methods are exposed on the Surface object. From 5.5.0 onwards these methods are exposed on the UIStatesPlugin.

  • activateState(stateId, [target])

Activate the given state, optionally on the given target. If target is not supplied then the state will be applied to the entire dataset.

  • deactivateState(stateId, [target])

Deactivate the given state, optionally on the given target. If target is not supplied then the state deactivation will be applied to the entire dataset.

  • resetState()

Deactivates all states across the entire dataset.


Wildcard states

In the above example, the state specification applied to all nodes, groups, edges and ports that have a type of default. Should you wish to indicate that a state can be applied to any object, you can use a wildcard:

  "states":{
"mintyGreenState":{
"*":{
cssClass:"mintyGreen"
},
"aSpecificType":{
cssClass:"FOO"
}
}
}

In this example, which contains only cssClass directives (remember that the cssClass will be added to all nodes, groups, ports and edges), when mintyGreenState is activated, all objects will get the mintyGreen CSS class. But objects of type aSpecificType will get the FOO CSS class also.