Skip to main content

Shape Sets

A ShapeSet is a set of named shapes that a ShapeLibrary can use to render SVG into vertex elements or a palette. The Toolkit currently ships with one set of shapes - FLOWCHART_SHAPES, but it is a straightforward process to make your own set.

Structure

This is the basic structure - here we show the header and a few shapes from the flowchart shapes that ship with the Toolkit:

export const FLOWCHART_SHAPES = {
id:"flowchart",
name:"Flowchart",
shapes:{
"process": {
type: "process",
label: "Process",
template: '<svg:rect x="{{sw}}" y="{{sw}}" width="{{width-(sw*2)}}" height="{{height-(sw*2)}}"/>'
},
"decision": {
type: 'decision',
label: "Decision",
template: '<svg:path d="M {{width/2}} {{sw}} L {{width-sw}} {{height/2}} L {{width/2}} {{height-sw}} L {{sw}} {{height/2}} Z"/>'
},
"collate": {
type: "collate",
template: `<svg:g><svg:path d="M {{sw/2}} {{sw/2}} L {{width-sw}} {{sw/2}} L {{width/2}} {{height/2}} Z"/>
<svg:path d="M {{sw/2}} {{height-(sw/2)}} L {{width-sw}} {{height-(sw/2)}} L {{width/2}} {{height/2}} Z"/>
</svg:g>`
}
}
}

Each shape must have at least a type and a template value; label is optional, and description is also supported.

Template format

The template must be in the format supported by the Toolkit's default templating engine, ie. XHTML, with every tag properly closed, and using a namespace prefix for SVG elements. Additionally, the template must have a single root element. Notice how in the collate template we use a group element as the root, and put the other SVG elements inside of that.

Variable interpolation

When a shape library renders a shape, it presents three variables to the template engine:

  • width When rendering a vertex this value will have been sourced from the vertex's backing data. When rendering a shape in a palette the palette sets a fixed value for this.

  • height When rendering a vertex this value will have been sourced from the vertex's backing data. When rendering a shape in a palette the palette sets a fixed value for this.

  • sw This is the stroke width to use in the resulting SVG. The various components of the shape library module default to a stroke width of 2 pixels, but you can override this. We include the stroke width in the template calculations in order to prevent clipping - theoretically it is possible to control stroke width via CSS but this does not always provide the best results. You do not need to include a sw value in your vertex backing data.

The template you provide is inserted as a child element of an SVG element, whose viewBox is set to 0 0 width height. With this arrangement, your SVG will scale seamlessly if the size of a node changes.

Available sets

The Toolkit currently ships with one shape set - FLOWCHART_SHAPES:

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

const myLibrary = new ShapeLibraryImpl(FLOWCHART_SHAPES)

These are the flowchart shapes:

Custom shape sets

It's straightforward to make your own shape set. Here we have made a set of faces:

const shapes = {
id:"faces",
shapes:{
impassive:{
type:"impassive",
template:`<svg:g>
<svg:circle cx="{{width/2}}" cy="{{height/2}}" r="{{(width/2) - (2*sw)}}"/>
<svg:path d="M {{width/4}} {{height*3/4}} L {{width*3/4}} {{height*3/4}}"/>
<svg:circle cx="{{width/4}}" cy="{{height/4}}" r="10"/>
<svg:circle cx="{{width*3/4}}" cy="{{height/4}}" r="10"/>
<svg:circle cx="{{width/2}}" cy="{{height/2}}" r="10"/>
</svg:g>`
},
pleased:{
type:"pleased",
template:`<svg:g>
<svg:circle cx="{{width/2}}" cy="{{height/2}}" r="{{(width/2) - (2*sw)}}"/>
<svg:circle cx="{{width/4}}" cy="{{height/4}}" r="10"/>
<svg:circle cx="{{width*3/4}}" cy="{{height/4}}" r="10"/>
<svg:circle cx="{{width/2}}" cy="{{height/2}}" r="10"/>
<svg:path d="M {{width/4}} {{height*3/4}} C {{width/4}} {{height*7/8}}, {{width*3/4}} {{height*7/8}} {{width*3/4}} {{height*3/4}}"/>
</svg:g>`
},
notpleased:{
type:"notpleased",
template:`<svg:g>
<svg:circle cx="{{width/2}}" cy="{{height/2}}" r="{{(width/2) - (2*sw)}}"/>
<svg:circle cx="{{width/4}}" cy="{{height/4}}" r="10"/>
<svg:circle cx="{{width*3/4}}" cy="{{height/4}}" r="10"/>
<svg:circle cx="{{width/2}}" cy="{{height/2}}" r="10"/>
<svg:path d="M {{width/4}} {{height*3/4}} C {{width/4}} {{height*5/8}}, {{width*3/4}} {{height*5/8}} {{width*3/4}} {{height*3/4}}"/>
</svg:g>`
}
}
}
Custom shapes