React Integration
JsPlumb has several components to assist you to integrate with React. We recommend React 17 or later, but some users have reported that they have apps running with JsPlumb in React 16. JsPlumb has been tested against React 17, React 18 and NextJS 14.0.3.
Imports
"dependencies":{
"@jsplumbtoolkit/browser-ui-react":"6.71.0"
}
Quick start
The main component you will use is the
SurfaceComponent
. Let's take a quick look at how you'd use one:
import React from "react"
import {
MiniviewComponent,
SurfaceComponent,
ControlsComponent
}
from '@jsplumbtoolkit/browser-ui-react';
export default function DemoComponent({someProps}) {
const data = {
nodes:[
{ id:"1", label:"1", left:50, top:50},
{ id:"2", label:"TWO", left:250, top:250}
],
edges:[
{ source:"1", target:"2" }
]
}
return <div style={{width:"100%",height:"100%"}}>
<SurfaceComponent data={data}>
<ControlsComponent/>
<MiniviewComponent/>
</SurfaceComponent>
</div>
}
In the above example the only prop we set on the
SurfaceComponent
was
data
, meaning the component uses a default
Absolute
layout and some default JSX for rendering nodes. The
SurfaceComponent
, though, is highly configurable, mainly through its
viewOptions
and
renderOptions
props. Here's the same example from before but with a few more things configured:
import React from "react"
import {
MiniviewComponent,
SurfaceComponent,
ControlsComponent
}
from '@jsplumbtoolkit/browser-ui-react';
export default function DemoComponent({someProps}) {
const data = {
nodes:[
{ id:"1", label:"1", left:50, top:50},
{ id:"2", label:"TWO", left:250, top:250}
],
edges:[
{ source:"1", target:"2" }
]
}
const viewOptions = {
nodes:{
default:{
jsx:(ctx) => <div style={{width:"60px", height:"60px", backgroundColor:"white", border:"1px solid black", text-align:"center"}}><h3>{ctx.data.label}</h3></div>
}
}
}
const renderOptions = {
layout:{
type:"ForceDirected"
},
grid:{
size:{
w:50, h:50
}
}
}
return <div style={{width:"100%",height:"100%"}}>
<SurfaceComponent data={data} renderOptions={renderOptions} viewOptions={viewOptions}>
<ControlsComponent/>
<MiniviewComponent/>
</SurfaceComponent>
</div>
}
Rendering Nodes and Groups
At the core of your UI will be a
SurfaceComponent
, which provides the canvas onto which nodes, groups and edges are drawn. In the
Quickstart
section above we show a couple of examples of the
SurfaceComponent
in action.
Each node or group in your UI is rendered as an individual component. In the first example above, we rely on JsPlumb's default JSX to render each node, but in the second we provide some JSX ourselves, although its quite simple. In a real world app your JSX will likely be more complex. As an example, consider the component we use to render nodes in the Flowchart Builder :
import * as React from 'react';
import { ShapeComponent } from "@jsplumbtoolkit/browser-ui-react"
import anchorPositions from "./anchor-positions"
export default function NodeComponent({ctx, shapeLibrary}) {
const { vertex, toolkit } = ctx;
const data = vertex.data;
return <div style={{color:data.textColor}} className="flowchart-object" data-jtk-target="true">
<ShapeComponent obj={data} shapeLibrary={shapeLibrary} showLabels={true} labelProperty="text"/>
{anchorPositions.map(ap => <div className={"jtk-connect jtk-connect-" + ap.id} data-jtk-anchor-x={ap.x} data-jtk-anchor-y={ap.y} data-jtk-orientation-x={ap.ox} data-jtk-orientation-y={ap.oy} data-jtk-source="true" data-jtk-port-type="source" key={ap.id}></div>)}
<div className="node-delete node-action delete" onClick={() => toolkit.removeNode(vertex)}></div>
</div>
}
The contents of the JSX used to render each node/group are entirely up to you.
Mapping types to JSX
The
viewOptions
prop is used to map node/group types to JSX, and to certain behaviours. For instance, this is the
nodes
section of the
viewOptions
for the flowchart builder starter app:
import { DEFAULT, newInstance } from "@jsplumbtoolkit/browser-ui"
import NodeComponent from "./NodeComponent.jsx"
const shapeLibrary = ...
const toolkit = newInstance(....)
const view = {
nodes: {
[DEFAULT]: {
jsx: (ctx) => {
return <NodeComponent ctx={ctx} shapeLibrary={shapeLibrary}/>
},
// connections to/from this node can exist at any of the given anchorPositions
anchorPositions,
// node can support any number of connections.
maxConnections: -1,
events: {
[EVENT_TAP]: (params) => {
surface.current.stopEditingPath()
// if zero nodes currently selected, or the shift key wasnt pressed, make this node the only one in the selection.
if (toolkit.getSelection()._nodes.length < 1 || params.e.shiftKey !== true) {
toolkit.setSelection(params.obj)
} else {
// if multiple nodes already selected, or shift was pressed, add this node to the current selection.
toolkit.addToSelection(params.obj)
}
}
}
}
},
}
To map a node/group type to some JSX, you're expected to provide a function that takes
ctx
as argument, and returns JSX.
ctx
is an object containing five things:
interface JsxContext {
vertex: Node | Group; // the vertex - node or group - that is being rendered by this JSX
surface: Surface; // the Surface widget that is rendering the vertex
toolkit: JsPlumbToolkit; // the underlying JsPlumbToolkit instance
data: Record<string, any>; // the vertex's backing data. This is just a convenience - it can be accessed via `vertex.data`
props: Record<string, any>; // these are any props that you passed in as the `childProps` argument to a `SurfaceComponent`. See below.
}
As mentioned above, you can pass back arbitrary JSX from these functions.
In this view you'll also see we pass a
shapeLibrary
in to each component - the demonstration uses a ShapeLibrary to draw the various flowchart shapes. What you pass in to your JSX is entirely your choice - JsPlumb gives you the
ctx
variable and you can use it how you like.
Passing props
You can pass props in to the components used to render your vertices by setting them on the
childProps
prop of a Surface component. For instance, in the
,
DemoComponent
- the main app - declares a random
color
variable in its initial state:
class DemoComponent extends React.Component {
constructor(props) {
super(props);
this.toolkit = jsPlumbToolkit.newInstance();
this.state = { color:randomColor() };
}
}
In the
render
method of the
DemoComponent
, a surface component is created, and the
color
member of the main component's state is passed in:
render() {
return <div style={{width:"100%",height:"100%",display:"flex"}}>
<button onClick={this.changeColor.bind(this)} style={{backgroundColor:this.state.color}} className="colorButton">Change color</button>
<SurfaceComponent childProps={{color:this.state.color}} renderOptions={this.renderOptions} toolkit={this.toolkit} view={this.view} />
</div>
}
In the
view
for the
DemoComponent
, each of the node types references the Surface's
childProps
by way of the context they are given:
this.view = {
nodes: {
"shin":{
jsx: (ctx) => { return <ShinBoneComponent color={ctx.props.color} ctx={ctx}/> }
},
"knee":{
jsx: (ctx) => { return <KneeBoneComponent color={ctx.props.color} ctx={ctx}/> }
}
},
...
}
So, here,
ctx.props.color
is referencing
this.state.color
in
DemoComponent
. If we change
DemoComponent
's state, the change propagates through to the vertex components:
changeColor() {
const current = this.state.color;
let col;
while (true) {
col = randomColor();
if (col !== current) {
break;
}
}
this.setState({ color:col } )
}
Context and Providers
JsPlumb React 6.40.0 has support for React's concepts of
Context
and
Providers
, and this offers a means for you to build apps with JsPlumb with far less boilerplate than was previously required. In the component discussions above you can see how
MiniviewComponent
and
ControlsComponent
can be nested inside a
SurfaceComponent
, and also how
PaletteComponent
was nested inside a
SurfaceProvider
- these are examples of providers and context in action.
For a primer on providers and context you can check out the React docs .
A
Context
is a means for some component to provide data to all of its descendants. JsPlumb React has two.
JsPlumbContext
This context contains an instance of the JsPlumb Toolkit - the underlying data model. A
JsPlumbContext
is created when a
JsPlumbProvider
is declared in your JSX. It's not as common to need a
JsPlumbContext
as it is to need a
SurfaceContext
: it's typically only needed in apps that wish to render one data model to more than one canvas.
SurfaceContext
This context contains a Surface. A
SurfaceContext
is created when:
SurfaceProvider
is declared in your JSX (see below); or
SurfaceComponent
is created and it is not inside an existing
SurfaceContext
In the component examples above, we see the
MiniviewComponent
and
ControlsComponent
declared without any props, as children of a
SurfaceComponent
. The
SurfaceComponent
populates a
SurfaceContext
with the surface it has created, and the
MiniviewComponent
and
ControlsComponent
discover the surface via the
SurfaceContext
:
<SurfaceComponent renderOptions={renderOptions}>
<ControlsComponent/>
<MiniviewComponent/>
</SurfaceComponent>
SurfaceProvider
This provider offers a means for you to share a surface located somewhere in your UI with other components that are not necessarily descendants of the surface component. A common use case is for
Inspectors
and
Palettes
- often you'll find they do not exist as children of the surface element but rather elsewhere in the DOM, for instance:
<div className="row">
<SurfaceProvider>
<div className="col-9">
<SurfaceComponent/>
</div>
<div className="col-3 d-flex flex-column">
<PaletteComponent selector="li" dataGenerator={dataGenerator} typeExtractor={typeExtractor}>
<ul>
<li data-node-type="foo" jtk-is-group="true">FOO</li>
<li data-node-type="bar">BAR</li>
</ul>
</PaletteComponent>
<InspectorComponent/>
</div>
</SurfaceProvider>
</div>
Here we see a UI using
Bootstrap
, consisting of a surface across 9 columns, and then a right hand pane containing a palette and an inspector. The
SurfaceProvider
is a common parent for all of the JsPlumb components.
JsPlumbProvider
This provides a
JsPlumbContext
- a typical use case is when you want to render some data model to more than one place.
<div className="row">
<JsPlumbProvider>
<div className="col-6">
<SurfaceComponent/>
</div>
<div className="col-6">
<SurfaceComponent/>
</div>
</JsPlumbProvider>
</div>
Shape libraries
A shape library is a set of named shapes that you will use to render SVG inside the vertices in your application. These are discussed in detail in the shape libraries and shape-sets pages; here we provide an overview of the available React integration with these modules.
Creating a shape library
In React, a shape library is created the same way as in vanilla js. In the code below we create a shape library with flowchart and basic shapes, which we then inject into our
SurfaceComponent
:
import React from 'react';
import { FLOWCHART_SHAPES, BASIC_SHAPES, ShapeLibraryImpl, DEFAULT } from "@jsplumbtoolkit/browser-ui"
import NodeComponent from './node-component'
export default function FlowchartComponent() {
const shapeLibrary = new ShapeLibraryImpl([FLOWCHART_SHAPES, BASIC_SHAPES])
const viewOptions = {
nodes: {
[DEFAULT]: {
jsx: (ctx) => {
return <NodeComponent ctx={ctx} />
}
}
}
}
return <div>
<SurfaceComponent viewOptions shapeLibrary={shapeLibrary}/>
</div>
Rendering an SVG shape
Shapes can be rendered with a
ShapeComponent
. This takes the
ctx
that JsPlumb passes into your JSX inside the view as a prop, from which it can extract the current vertex and the underlying surface, plus the shape library the surface is using:
import * as React from 'react';
import { ShapeComponent } from "@jsplumbtoolkit/browser-ui-react"
export default function NodeComponent({ctx}) {
return <div className="my-class">
<ShapeComponent ctx={ctx} />
</div>
}
By default the shape component will render just the shape. If you want to add labels you can do so like this:
import * as React from 'react';
import { ShapeComponent } from "@jsplumbtoolkit/browser-ui-react"
export default function NodeComponent({ctx}) {
return <div className="my-class">
<ShapeComponent ctx={ctx} showLabels={true} labelProperty="text"/>
</div>
}
The full list of props is available below .
Adding your own shapes
To add your own shapes, you'll need to create a shape set. These are discussed on a separate page .
Dragging new nodes/groups
Palettes offer a means for your users to drag new nodes/groups onto your canvas. The
PaletteComponent
is the main component you'll use; there's also a
ShapeLibraryPaletteComponent
which is a specialised version of the
PaletteComponent
that sources its draggable nodes from a
ShapeLibrary
.
HTML elements
To configure your UI to drag and drop HTML elements onto your canvas, you'll use a
PaletteComponent
. Here's how to set one up:
import { PaletteComponent, SurfaceComponent, SurfaceProvder } from '@jsplumbtoolkit/browser-ui-react';
export default function MyApp() {
const dataGenerator = function (type) { return { w:120, h:80, type:el.getAttribute("data-node-type") } };
return <div className="row">
<SurfaceProvider>
<div className="col-9">
<SurfaceComponent/>
</div>
<div className="col-3">
<PaletteComponent selector="li" dataGenerator={dataGenerator}>
<ul>
<li data-node-type="foo" jtk-is-group="true">FOO</li>
<li data-node-type="bar">BAR</li>
</ul>
</PaletteComponent>
</div>
</SurfaceProvider>
</div>
}
The basic contract is that you declare a
PaletteComponent
in your JSX, and you provide - at the minimum - a
selector
, which tells the palette component how to find which children of the component are draggable. You then write out the children however you like - in this case we use a
ul
and an
li
for each draggable type.
The
PaletteComponent
needs to know which surface it is going to be attached to, and it does this by being context aware - in the code above we have a
SurfaceProvider
wrapping both the surface component and the palette component. When the surface component is instantiated, it populates the surface provider's context, and the palette component is notified of the surface to use.
In the code above we also see a
dataGenerator
prop:
dataGenerator
provides a means for the component to generate an initial data payload for some node that is being dragged. You can read about the full list of available props in the
component list below
.
SVG shapes
To drag and drop SVG shapes, you can use a
ShapeLibraryPaletteComponent
. This is a specialised version of the
PaletteComponent
which sources its draggable nodes from a
ShapeLibrary
.
import React, { useEffect, useRef} from 'react';
import { FLOWCHART_SHAPES, BASIC_SHAPES, ShapeLibraryImpl } from "@jsplumbtoolkit/browser-ui"
import { ShapeLibraryPaletteComponent, SurfaceComponent, SurfaceProvider } from "@jsplumbtoolkit/browser-ui-react"
export default function FlowchartComponent() {
const shapeLibrary = new ShapeLibraryImpl([FLOWCHART_SHAPES, BASIC_SHAPES])
const dataGenerator = function (type) { return { w:120, h:80, type:el.getAttribute("data-node-type") } };
return <div>
<SurfaceProvider>
<SurfaceComponent viewOptions={viewOptions} shapeLibrary={shapeLibrary}/>
<ShapeLibraryPaletteComponent className="node-palette"
dataGenerator={dataGenerator} initialSet={FLOWCHART_SHAPES.id}/>
</SurfaceProvider>
</div>
As with
PaletteComponent
, the
ShapeLibraryPaletteComponent
is context aware and can locate the surface to use from a
SurfaceProvider
.
Component List
This is a full list of the components that are available in JsPlumb React. For each we provide a sample usage, which does not necessarily use all of the props available for the given component. We then provide the full list of available props.
SurfaceComponent
The key UI component you'll use to render your UI.
<SurfaceComponent renderOptions={someRenderOptions}
viewOptions={someViewOptions}/>
Interface SurfaceComponentProps
Name | Type | Description |
---|---|---|
childProps
?
|
any | Any props to pass to children. |
className
?
|
string | Optional class name to append to the root element's class list. |
data
?
|
any | Optional initial data |
modelOptions
?
|
JsPlumbToolkitOptions |
Options for the underlying JsPlumb Toolkit instance. If you use this component as a child of a
JsPlumbComponent
then the underlying JsPlumb instance will be sourced
from the JsPlumbComponent. Otherwise, this component will instantiate a JsPlumb instance itself, optionally using these params.
|
renderOptions
?
|
ReactSurfaceRenderOptions | Render options such as layout, drag options etc |
shapeLibrary
?
|
ShapeLibraryImpl |
Optional shape library for the underlying surface to use. You can provide this or you can
also provide a
shapes
render option to the surface.
|
surfaceId
?
|
string | Optional ID to assign to the surface that is created. |
toolkit
?
|
BrowserUIReact | JsPlumb instance to use - optional. The SurfaceComponent will create find a JsPlumb instance in an enclosing JsPlumbContext, if applicable, or otherwise will create its own JsPlumb instance (for which you can provide modelOptions if you wish) |
url
?
|
string | Optional URL to load initial data from. |
viewOptions
?
|
ReactSurfaceViewOptions | Mappings of vertex types to components/jsx and edge types. |
MiniviewComponent
Provides a Miniview of the contents of some surface. This component can be nested inside a
SurfaceComponent
, from which it will find the surface to attach to, or it can also exist as a descendant of a
SurfaceProvider
- the approach you choose will depend on the structure of your page.
Example
export default function MyComponent() {
return <SurfaceComponent renderOptions={renderOptions}>
<MiniviewComponent/>
</SurfaceComponent>
}
Interface MiniviewComponentProps
Name | Type | Description |
---|---|---|
activeTracking
?
|
boolean | Whether or not to move miniview elements at the same time as their related surface element is being dragged. Defaults to true. |
className
?
|
string | Optional class name to append to the root element's class list. |
clickToCenter
?
|
boolean | Defaults to true, meaning a click on a node/group in the miniview will cause that node/group to be centered in the related surface. |
elementFilter
?
|
Optional filter to decide which elements to show in the miniview. | |
typeFunction
?
|
Optional function to use to decorate miniview elements with a
jtk-miniview-type
attribute. Can be used for simple styling.
|
ControlsComponent
Provides a component that offers a set of controls for some surface. If there is a lasso plugin installed on the given surface this component will show buttons for pan/select mode, otherwise it will not. This component can be nested inside a
SurfaceComponent
, from which it will find the surface to attach to, or it can also exist as a descendant of a
SurfaceProvider
- the approach you choose will depend on the structure of your page.
Example
export default function MyComponent() {
return <SurfaceComponent renderOptions={renderOptions}>
<ControlsComponent/>
</SurfaceComponent>
}
Props
Interface ControlsComponentProps
Name | Type | Description |
---|---|---|
buttons
?
|
ControlsComponentButtons | Optional extra buttons to add to the controls component. |
className
?
|
string | Optional class name to append to the root element's class list. |
clear
?
|
boolean | Whether or not to show the clear button, defaults to true. |
clearMessage
?
|
string |
Optional message for the alert that the clear button shows by default. Defaults to
Clear dataset?
.
|
onMaybeClear
?
|
Optional callback to invoke when the user presses the clear button. If you provide this, the component will not show an alert and instead call this method, passing in a function you can invoke if you wish to continue with the clear operation. | |
orientation
?
|
Optional orientation for the controls. Defaults to 'row'. | |
surfaceId
?
|
string | The ID of surface to attach to. Optional. |
undoRedo
?
|
boolean | Whether or not to show undo/redo buttons, defaults to true |
zoomToExtents
?
|
boolean | Whether or not to show the zoom to extents button, defaults to true |
ExportControlsComponent
Provides a component that offers a set of buttons users can click to generate SVG, PNG or JPG output of the canvas.
Example
export default function MyComponent() {
return <SurfaceComponent renderOptions={renderOptions}>
<ExportControlsComponent/>
</SurfaceComponent>
}
Props
Interface ExportControlsComponentProps
Name | Type | Description |
---|---|---|
allowJpgExport
?
|
boolean | Defaults to true. |
allowPngExport
?
|
boolean | Defaults to true. |
allowSvgExport
?
|
boolean | Defaults to true. |
imageOptions
?
|
ImageExportUIOptions | Options for image exports. |
label
?
|
string | What to show in the label, if visible. Defaults to "Export:". |
margins
?
|
PointXY | Optional margins to apply to both SVG and image exports. Will not override any margins specified in svgOptions or imageOptions. |
showLabel
?
|
boolean | Whether or not to show a label in front of the buttons. Defaults to true. |
surfaceId
?
|
string | The ID of surface to attach to. Optional. |
svgOptions
?
|
SvgExportUIOptions | Options for SVG exports. |
PaletteComponent
Provides a means to implement drag/drop of new Nodes/Groups onto your Surface. This component can be nested inside a
SurfaceComponent
, from which it will find the surface to attach to, or it can also exist as a descendant of a
SurfaceProvider
- the approach you choose will depend on the structure of your page.
Example
import { PaletteComponent, SurfaceComponent, SurfaceProvder } from '@jsplumbtoolkit/browser-ui-react';
export default function MyApp() {
const typeExtractor = function(el) { return el.getAttribute("data-node-type") };
const dataGenerator = function (type) { return { w:120, h:80 }; };
return <div className="row">
<SurfaceProvider>
<div className="col-9">
<SurfaceComponent/>
</div>
<div className="col-3">
<PaletteComponent selector="li" dataGenerator={dataGenerator} typeExtractor={typeExtractor}>
<ul>
<li data-node-type="foo" jtk-is-group="true">FOO</li>
<li data-node-type="bar">BAR</li>
</ul>
</PaletteComponent>
</div>
</SurfaceProvider>
</div>
}
Props
Interface PaletteComponentProps
Name | Type | Description |
---|---|---|
allowDropOnCanvas
?
|
string | Whether or not to allow drop on whitespace in the canvas. Defaults to true. |
allowDropOnEdge
?
|
string | Whether or not to allow drop on edge. Defaults to false. |
allowDropOnGroup
?
|
string | Whether or not to allow drop on existing vertices. Defaults to true. |
children
?
|
Child elements. Although this is optional it is expected there will be some - otherwise the palette does nothing. | |
className
?
|
string | Optional extra css classes to set on the element |
dataGenerator
?
|
DataGeneratorFunction | Function to use to get a dataset for an item that is being dragged. |
groupIdentifier
?
|
GroupIdentifierFunction | Function to use to determine whether an item that is being dragged represents a group. |
selector
|
string |
CSS 3 selector identifying what child elements of
container
are draggable.
|
surface
?
|
Surface | The surface to attach to. Optional: this component can derive a surface from a SurfaceProvider or SurfaceComponent. |
typeGenerator
?
|
TypeGeneratorFunction | Function to use to get the type of an item that is being dragged. |
ShapeLibraryPaletteComponent
This is a specialised version of the
PaletteComponent
which sources its draggable nodes from a
ShapeLibrary
.
Example
import React, { useEffect, useRef} from 'react';
import { FLOWCHART_SHAPES, BASIC_SHAPES, ShapeLibraryImpl } from "@jsplumbtoolkit/browser-ui"
import { ShapeLibraryPaletteComponent, SurfaceComponent, SurfaceProvider } from "@jsplumbtoolkit/browser-ui-react"
export default function FlowchartComponent() {
const shapeLibrary = new ShapeLibraryImpl([FLOWCHART_SHAPES, BASIC_SHAPES])
const dataGenerator = function (type) { return { w:120, h:80, type:el.getAttribute("data-node-type") } };
return <div>
<SurfaceProvider>
<SurfaceComponent viewOptions={viewOptions}/>
<ShapeLibraryPaletteComponent className="node-palette"
shapeLibrary={shapeLibrary} dataGenerator={dataGenerator} initialSet={FLOWCHART_SHAPES.id}/>
</SurfaceProvider>
</div>
Props
Interface ShapeLibraryPaletteComponentProps
Name | Type | Description |
---|---|---|
canvasStrokeWidth
?
|
number | Stroke width to use for shapes dropped on canvas. Defaults to 2. |
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. |
initialSet
?
|
string | ID of the initial set to show, if any. When you have multiple shapes in a set you may want the palette to open up showing just one set. |
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
?
|
ShapeLibraryImpl | 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. Optional; this component can extract the Surface from a SurfaceProvider, or from being a child of a SurfaceComponent. |
ShapeComponent
This component is used in conjunction with a
ShapeLibrary
to render SVG shapes.