Skip to main content

Shape Libraries

A shape library contains one or more sets of named shapes that you will use to render SVG inside the vertices in your application. These are an ideal solution for all sorts of diagrams. The type of each vertex is used by the Toolkit to look up an appropriate shape to render, and when you have more than one set of shapes, the Toolkit uses each vertex's category value to pick the set to use for a given shape.

note

This functionality is only available from version 6.2.0 of the Toolkit. Prior versions of the Toolkit do not offer this functionality.

Setup

You'll first need to create a ShapeLibraryImpl and pass in a set of shapes to render:

import { FLOWCHART_SHAPES, ShapeLibraryImpl } from "@jsplumbtoolkit/browser-ui"

const shapeLibrary = new ShapeLibraryImpl(FLOWCHART_SHAPES)

You can use this shape library to do a couple of things:

Shape sets

A shape library is a wrapper around one or more shape sets. Here we use FLOWCHART_SHAPES - this is a set of shapes that ship with the Toolkit. You can read about the available shapes (and how to create your own set) on this page.

Rendering SVG into nodes

Note: this section discusses how to use a shape library to render SVG when you're using the Toolkit's vanilla templating mechanism. If you're using a library integration (Angular, React etc) you should check the docs for the library integration to find out how to perform the equivalent of what is discussed in this section.

Requirements

There are two things you need to configure - your node data, and a tag to render the SVG.

Node data

Your node data must contain:

  1. A type field that maps to the ID of one of the shapes in your library
  2. A width and height value for each node. The SVG shapes use path elements internally, which require absolute coordinates, and so they need to know the current size of your vertices:
{
"id": "1",
"name": "Some Node",
"type": "process",
"width": 200,
"height": 200
}
Flowchart shapes
In this example we have these two nodes:
[
{
"id":"1",
"left":50,
"top":50,
"type":"process",
"width":100,
"height":100,
"fill":"white",
"outline":"black",
"name": "Node 1"
},
{
"id":"2",
"left":150,
"top":250,
"type":"terminus",
"width":100,
"height":100,
"fill":"white",
"outline":"black",
"name": "Node 2"
}
]

Notice how each of the nodes has a type, width and height property in its data. Also note the fill and outline values - these are optional, and can be used to control the, er, fill and outline. If you do not provide values for these you'll get the default SVG behaviour, which is, in most browsers, to use a fill of "black". You can use CSS to apply a style to every node at once if individual fill and outline is not something you need to control:

.jtk-node svg {
fill:white;
stroke:black;
}
Registering the shape library

To get the Surface to render the individual SVG shapes you need to provide a shapes object in your render params, with a reference to the library you have created. The render params used to generate the output above are:


const shapeLibrary = new ShapeLibraryImpl(FLOWCHART_SHAPES)

const renderParams = {
shapes:{
library:shapeLibrary
},
layout:{
type:AbsoluteLayout.type
},
defaults:{
anchor: AnchorLocations.AutoDefault,
endpoint: BlankEndpoint.type,
connector: OrthogonalConnector.type
},
zoomToFit:true,
view:{
nodes:{
default:{
template:`<div>
<jtk-shape/>
</div>`
}
},
edges:{
default:{
overlays:[
{
type:ArrowOverlay.type,
options:{
location:1
}
}
]
}
}
},
consumeRightClick:false
}

Note the jtk-shape element in the template? The Surface added this custom tag as a result of us providing the shape library to its render parameters.

Displaying labels

You can request that the shape library render a label in the center of each of your nodes:

Flowchart shapes
To do this we updated the `shapes` parameters from before:
shapes:{
library:shapeLibrary,
showLabels:true,
labelAttribute:"name"
}

By default, the shape library will look for a data property label in your node data. Here we have overridden that and told it to get the label from the node's name property.

SVG shape tag

An alternative way to register the tag is manually, with a name you choose. This is only recommended if, for some reason, you don't want to use jtk-shape in your templates, or if you have more than one shape library. To do this you replace the shapes entry with tags:

const renderParams = {
tags:{
"jtk-shape":shapeLibrary.getShapeTagDefinition()
},
layout:{
type:AbsoluteLayout.type
},
etc

Shape library palettes

A common requirement in apps that use a library of shapes is the ability to drag new shapes onto the canvas. The Toolkit offers drag/drop of new nodes via its SurfaceDropManager and DropManager classes, but in 6.2.0 we added a class that wraps the SurfaceDropManager with a shape library - the ShapeLibraryPalette.

To create a ShapeLibraryPalette you first need to have created a shape library, as shown above. Then:

const palette = new ShapeLibraryPalette({
container:someDOMElement,
surface:someSurface,
shapeLibrary:aShapeLibrary
})

Adding this to the code we had above, we get this result. Elements can be dragged from the palette onto the canvas. Note that when you drag an element from the palette it is automatically scaled to match the zoom of the canvas at that time:

:::note When you attach a shape library palette to a surface, the palette will automatically register the `jtk-shape` tag for you: you do not need to include the `tags` section in your render params as shown in the examples at the top of this page. :::

The full list of options for the ShapeLibraryPalette class are as follows:

Interface ShapeLibraryPaletteOptions

Options for a shape library palette.

Members

canvasStrokeWidth?: number
Stroke width to use for shapes dropped on canvas. Defaults to 2.
container: HTMLElement
The element to draw the palette into.
dataGenerator?: DataGeneratorFunction
Optional data generator to allow you to specify initial data for some element to be dragged. Note that you cannot override the object's type with this function. The palette will set the new object's type to match the type of the element that the user is dragging from the palette.
dragSize?: Size
Optional size to use for dragged elements.
fill?: string
Optional fill color to use for dragged elements. This should be in RGB format, _not_ a color like 'white' or 'cyan' etc.
iconSize?: Size
Optional size to use for icons. Defaults to 150x100 pixels. If you provide this but not dragSize this size will also be used for an icon that is being dragged.
initialSet?: string
Optional ID of the first set to show, hiding the others.
onVertexAdded?:
Optional callback to invoke when a new vertex has been added
outline?: string
Optional color to use for outline of dragged elements. Should be in RGB format.
paletteStrokeWidth?: number
Stroke width to use for shapes in palette. Defaults to 1.
selectAfterDrop?: boolean
When true (which is the default), a newly dropped vertex will be set as the underlying Toolkit's selection.
shapeLibrary: ShapeLibrary
The shape library to render.
showAllMessage?: string
Message to use for the 'show all' option in the shape set drop down when there is more than one set of shapes. Defaults to Show all.
surface: Surface
Surface to attach the drag/drop to.

Getting notification of a new vertex

As with the SurfaceDropManager that the ShapeLibraryPalette wraps, you can provide an onVertexAdded callback, which will be invoked whenever a new shape was dragged onto the canvas:

const palette = new ShapeLibraryPalette({
container:someDOMElement,
surface:someSurface,
shapeLibrary:aShapeLibrary,
onVertexAdded(vertex, dropTarget) => {

}
})

vertex is the new vertex that was added. In the event that the new vertex was dropped on top of some existing node, dropTarget will be provided, containing information about the node onto which the new vertex was dropped, as well as its position and size. dropTarget is of this type:


Export to SVG, PNG and JPG

As of version 6.6.0 you can export a UI that uses a shape library to SVG, PNG or JPG. See this page for more details.