NEW FUNCTIONALITY
- Shape libraries now support
defs
- snippets of SVG that you can declare in the header of a shape set and reference in the individual templates. This reduces bloat and increases readability. See below for more detail.
UPDATES
- Improvements to the hierarchy layout's crossing stage to reduce the chance of overlapping edges
- Improvements to SVG/PNG/JPG export UI
- Improvements to SVG export output: edges are drawn first in the SVG so that nodes will be placed on top in non-browser settings.
Shape Library Defs
In most UIs there is some amount of markup that is common amongst a number of vertices. For instance, in the network topology diagram below, there are three types of nodes - terminal
, cloud
and switch
, each of which has its own icon representing it:
In version 6.8.0 we have added support for a defs
element to shape sets - it is a wrapper for the defs element in SVG. The benefits of using defs are that you can reduce the number of elements in your DOM, and when exporting the SVG the resulting file will be smaller and easier to comprehend.
To configure this, we created a shape set like this:
const shapes = {
id: "networkTopology",
name: "NetworkTopology",
defs:{
"jtk-switch":`<svg:svg viewBox="0 0 1024 1024">
<svg:path d="..."/>
</svg:svg>`,
"jtk-cloud":`<svg:svg viewBox="0 0 100 100">
<svg:path d="..."/>
</svg:svg>`,
"jtk-terminal":`<svg:svg viewBox="0 0 32 32">
<svg:path d="..." />
</svg:svg>`
},
shapes: {
"cloud": {
type: "cloud",
template: `<svg:use xlink:href="#jtk-cloud" x="0" y="0" width="60" height="60"/>`
},
"switch": {
type: "switch",
template: `<svg:use xlink:href="#jtk-switch" x="0" y="0" width="60" height="60"/>`
},
"terminal": {
type: "terminal",
template: `
<svg:g>
<svg:use xlink:href="#jtk-terminal" x="0" y="0" width="60" height="60"/>
<svg:text x="30" y="25" text-anchor="middle" dominant-baseline="middle" stroke-width="0.25px">{{label}}</svg:text>
</svg:g>
`
}
}
}
I've truncated the actual SVG elements for readability's sake, but these are the things to note:
- Each
def
has ansvg
element at its root, with aviewBox
. This is not essential, but in this case our icons came from various different places and had different base sizes. TheviewBox
allows us to map them to the size we want. - Each def has a single root element. This is mandatory. Use an
svg:g
element as the root if you want to group a few elements. - The markup for each def is parsed by the Toolkit's default template engine and therefore must include namespaces and be XHTML, ie. no unclosed tags.
- The IDs of the various defs must be unique in the window, so choose carefully. We typically prefix with a namespace (
jtk-
here).
We then render a surface using this shape library:
import { newInstance, ShapeLibraryImpl, DEFAULT } from "@jsplumbtoolkit/browser-ui"
const shapes = {...}
const sl = new ShapeLibraryImpl([shapes])
const tk = newInstance()
tk.render(container, {
...
shapes:{
library:sl
},
view:{
nodes:{
[DEFAULT]:{
template:`
<div data-jtk-target="true" style="width:60px;height:60px;">
<jtk-shape width="60" height="60"/>
</div>`
}
}
}
})
Further reading
You can read up on this in our documentation - https://docs.jsplumbtoolkit.com/toolkit/6.x/lib/shape-sets.
Start a free trial
Get in touch!
If you'd like to discuss any of the ideas/concepts in this article we'd love to hear from you - drop us a line at hello@jsplumbtoolkit.com.