Skip to main content

Vue 3 Integration

The jsPlumb Toolkit has several components to assist you in integrating with Vue 3. These are shipped in the package @jsplumbtoolkit/browser-ui-vue3.

Vue3 versions of our Flowchart Builder, Schema Builder and Chatbot starter apps are available in the starter apps repository on Github.

We'll refer to this demonstration occasionally in this document.


Imports

"dependencies": {
...
"@jsplumbtoolkit/browser-ui-vue3":"^6.0.0"
...
},

Setup

The Toolkit's Vue3 components are shipped with precompiled templates, meaning you need to import the Toolkit in your Vue bootstrap code. For instance, this is the bootstrap routine from the Flowchart demonstration:

Bootstrap

import { createApp } from 'vue'
import App from './App.vue'

import { JsPlumbToolkitVue3Plugin } from "@jsplumbtoolkit/browser-ui-vue3"

const app = createApp(App)
app.use(JsPlumbToolkitVue3Plugin)

Components

The Toolkit offers 2 components and 3 mixins:

jsplumb-toolkit

This component provides an instance of the Toolkit and a surface widget to render the contents. You do not instantiate either the Toolkit or the Surface yourself, the Vue 3 code handles that. If you subsequently want to access the Toolkit instance a good approach is to declare a ref for the Toolkit component as shown below. After the example follows a brief discussion of how to get access to the Toolkit and to the Surface.

Example

<jsplumb-toolkit 
ref="toolkitComponent"
id="toolkit"
surface-id="surfaceId"
v-bind:render-params="this.renderParams()"
v-bind:toolkit-params="this.toolkitParams()"
v-bind:view="this.viewParams()">

</jsplumb-toolkit>

Attributes

All attributes are optional. Note that Vue prefers "kebab case" for attribute names, even if the actual property is camel case on the component (and of course Javascript does not like kebab case for property names).

  • id Unique ID for the Toolkit instance. Can be used to retrieve a Toolkit instance from the jsPlumbToolkitVue3 module.
  • surface-id Unique ID for the Surface widget. Required if you wish to attach a Miniview or a Palette. Also useful if you wish to interact with a Surface, to perform operations such as zooming, centering on content, etc.
  • render-params Parameters to pass in to the constructor of the Surface widget. Note here we use the v-bind: prefix to tell Vue that the object we are injecting is in the Vue instance's model.
  • toolkit-params Parameters to pass in to the constructor of the Toolkit instance. Note again the use of v-bind: in our example above.
  • view View parameters. Views are discussed here.

In this example we supply render-params, toolkit-params and view to the return value of methods - the underlying code looks like this:

export default defineComponent({
name: 'some-component',
props:["surfaceId"],
methods:{
viewParams:function() {
return {
nodes: {
"start": {
component:StartNode
},
...other node types
},
... rest of the view
}
},
toolkitParams:function() {
return {
beforeStartConnect: (node) => {
// limit edges from start node to 1. if any other type of node, return
return (node.data.type === START && node.getEdges().length > 0) ? false : {label: "..."};
}
}
},
renderParams:function() {
return {
layout:{
type:SpringLayout.type
},
... other render params.
]
}
}
})

Accessing the Toolkit and the Surface

You'll almost certainly want to access the underlying Toolkit instance, which is best done by declaring a ref as shown above. This ref can be accessed when the component mounts, as in the snippet below. We also show here how to access a surface, which you do via the loadSurface method from the Vue 3 integration package:


import { loadSurface } from '@jsplumbtoolkit/browser-ui-vue3';

let toolkit

export default defineComponent({

mounted() {
toolkit = this.$refs.toolkitComponent.toolkit
loadSurface("surfaceId", (s) => {
// s is of type Surface.
})
}
})

loadSurface takes a callback rather than passing the surface back directly. This is because there is no guarantee that a surface with the given ID exists - it may be not loaded yet. If you try to access a surface that is not yet loaded, your request is queued, and then subsequently when a surface with that ID is registered on the Vue integration all of the requests for that surface are served, in the order they originally arrived.


jsplumb-miniview

This is a component that provides a miniview that can be attached to some surface.

Example

<jsplumb-miniview surface-id="surfaceId"></jsplumb-miniview>

Attributes

  • surface-id ID for the surface widget to which to attach the Miniview.

SurfaceDrop mixin

This mixin is a wrapper around the Drop Manager, which offers the ability to drop onto edges, nodes and the canvas itself.

Example

This is an example of a component that uses the SurfaceDrop mixin. We show, in the onCanvasDrop method, an example of how this mixin can be used to replace the previous Palette mixin. Note, though, the onEdgeDrop and onDrop methods: these are, respectively, called when an element is dragged on an Edge or a Node/Group.

<template>
<div class="sidebar node-palette">
<div class="sidebar-item" :data-node-type="entry.type" title="Drag to add new" v-for="entry in data" :key="entry.type">
<i :class="entry.icon"></i>{{entry.label}}
</div>
</div>
</template>

<script>

import { SurfaceDrop } from '@jsplumbtoolkit/browser-ui-vue3-drop';

export default {
mixins:[ SurfaceDrop ],
data:function() {
return {
data:[
{ icon:"icon-tablet", label:"Question", type:"question" },
{ icon:"icon-eye-open", label:"Action", type:"action" },
{ type:"output", icon:"icon-eye-open", label:"Output" }
]
};
}
}

</script>

Note that this component itself doesn't declare any props, and you are free to provide any template you wish to render the component's data. The underlying DragDrop mixin's props are:

  • surfaceId:string Required. The ID of the Surface to which to attach the Drop Manager.
  • selector:string Required. A CSS3 selector instructing the Toolkit how to identify which elements in the component represent draggable node types.
  • dataGenerator:(el:HTMLElement) => T Optional. A function that can return a data object representing an element which is being dragged. This function is called as soon as an element starts to be dragged.
  • allowDropOnGroup:boolean Optional, defaults to true. If true, then elements can be dropped onto nodes/groups, and in the event that occurs, the onDrop method will be called.
  • allowDropOnCanvas:boolean Optional, defaults to true. When an element is dropped on the canvas whitespace, it is added to the dataset and rendered.
  • allowDropOnEdge:boolean Optional, defaults to true. If true, then elements can be dropped onto edges, and in the event that an element is dropped on an edge, a new node/group is added and inserted between the source and target of the original edge, and the original edge is discarded..
  • typeGenerator:(data:T) => string Optional. A function that can return the correct type for some data object representing an element being dragged. By default the Toolkit will use the type member of the data object.
  • groupIdentifier:(d: T, el: HTMLElement) => boolean Optional. By default, the toolkit looks for a jtk-is-group attribute on an element being dragged. If found, with a value of "true", then the Toolkit assumes a group is being dragged. You can supply your own function to make this decision.

TOP


BaseNodeComponent

This mixin should be included in any component you will use to render a node (see below for discussion of this). Several helper methods are exposed by this mixin:

  • getNode() Gets the underlying Toolkit node that the component is rendering
  • removeNode() Instructs the Toolkit to remove the node that the component is rendering. This will of course result in the destruction of the component.
  • getToolkit() Gets the underlying Toolkit instance for the node the component is rendering.
  • updateNode(data:any) Updates the underlying node that the component is rendering.

Nodes rendered with this mixin are fully reactive: calls to updateNode will result in a repaint of the component with no further effort involved on your part.

BaseGroupComponent

This mixin should be included in any component you will use to render a group (see below for discussion of this). Several helper methods are exposed by this mixin:

  • getGroup() Gets the underlying Toolkit group that the component is rendering
  • removeGroup(removeChildNodes?:boolean) Instructs the Toolkit to remove the group that the component is rendering, and possibly all of the child nodes of the group too. This will of course result in the destruction of the component.
  • getToolkit() Gets the underlying Toolkit instance for the group the component is rendering.
  • updateGroup(data:any) Updates the underlying group that the component is rendering.

Groups rendered with this mixin are fully reactive: calls to updateGroup will result in a repaint of the component with no further effort involved on your part.


Rendering Nodes and Groups

To render nodes and groups you need to do 3 things:

  • create a component
  • import it into the code that's handling your Toolkit instance
  • map it via the view.

Imagine you make this component inside MyNode.vue:

<template>
<div>
<h1>{{obj.label}}</h1>
<button v-on:click="clicked()">CLICK ME</button>
</div>
</template>


<script>
import { BaseNodeComponent } from "@jsplumbtoolkit/browser-ui-vue3";

export default {
mixins:[ BaseNodeComponent ],
methods:{
clicked:function() {
alert(this.getNode().data.label);
}
}
}
</script>

And you make this component, to manage an instance of the Toolkit:

<template>
<jsplumb-toolkit
ref="toolkitComponent"
url="flowchart-1.json"
v-bind:render-params="renderParams"
v-bind:view="view"
id="toolkit"
surface-id="surface"
v-bind:toolkit-params="toolkitParams">
</jsplumb-toolkit>
</template>

<script>

import MyNode from './MyNode.vue';

export default {

name: 'jsp-toolkit',
props:["surfaceId"],
data:() => {
renderParams:{ ... },
view:{
nodes:{
default:{
component:MyNode
}
}
}
}
}
</script>

MyNode is mapped to the component used to render nodes of type "default" (which for the Toolkit means any node). The jsplumb-toolkit declaration in the template is the one from the Flowchart Builder, which is a good place to look to get a feel for how a whole application can be built using the Toolkit.

Injecting values in nodes/groups

From version 5.13.7 onwards, you can provide a set of data values that you'd like to inject into a component via the inject property of a node definition:

export default {

name: 'jsp-toolkit',
props:["surfaceId"],
data:() => {
renderParams:{ ... },
view:{
nodes:{
default:{
component:MyNode,
inject:{
injectedStaticValue:"My Static Value",
injectedDynamicValue:(node, toolkit) => `My Dynamic Value ${node.id}`
}
}
}
}
}
}

Each value you inject can be either a static value, or a function that takes as argument the current node (or group) and the underlying Toolkit instance, and which returns an appropriate value.

In the component itself you need to declare these in the props:

props:{
injectedStaticValue:String,
injectedDynamicValue:String
},

You can then access these values in your template:

<template>
<div class="injected-static">{{injectedStaticValue}}</div>
<div class="injected-dynamic">{{injectedDynamicValue}}</div>
</template>

Rendering Ports

The Vue 3 integration supports rendering ports. A good example for how to do this can be found in the code for the Schema Builder starter application.


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 Vue 3 integration with these modules.

The Vue 3 integration has a plugin to assist you working with shape libraries. To enable it, you need to import it in your setup:

import Vue from 'vue'
import App from './App.vue'

import { JsPlumbToolkitVue3Plugin, ShapeLibraryPlugin} from '@jsplumbtoolkit/browser-ui-vue3'

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)
app.use(JsPlumbToolkitVue3Plugin, {})
app.use(ShapeLibraryPlugin, {})
app.mount('#app')

Rendering shapes

Once you've imported the shape library plugin, there will be jsplumb-shape component available to all of your components. In your main component - the one in which you declare your view - you need to instantiate a shape library, and then you need to inject it into each of your vertex components:


<script>

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

import MyVertexComponent from './MyVertexComponent.vue'

const shapeLibrary = new ShapeLibraryImpl([FLOWCHART_SHAPES, BASIC_SHAPES])

export default {
name:"flowchart",
...,
data:() => {
return {
renderParams:{ ... },
view:{
nodes:{
default:{
component:MyVertexComponent,
inject:{
shapeLibrary:shapeLibrary
}
}
}
}
}
}
}
</script>
<template>
<div>
<jsplumb-toolkit ref="toolkitComponent"
surface-id="surfaceId"
v-bind:render-params="renderParams"
v-bind:view="view">
</jsplumb-toolkit>
</div>
</template>

Anything inside the inject mapping for a component inside your view will be available as a class member on that component - above we injected our shape library.

Then inside your vertex components you can render shapes:

<script>

import { BaseNodeComponent } from '@jsplumbtoolkit/browser-ui-vue2'

export default {
mixins:[BaseNodeComponent]
}

</script>
<template>
<div>
<span>{{obj.text}}</span>
<jsplumb-shape :obj="obj" :shape-library="shapeLibrary"></jsplumb-shape>
</div>
</template>

Shape Library Palettes

The shape library plugin also makes available a jsplumb-shape-palette component, which lets you drag and drop new shapes from a palette:

To use it, you need to have setup the shape library as shown above. Then, in your template:

<jsplumb-shape-palette surface-id="surfaceId"
:shape-library="shapeLibrary"
:data-generator="dataGenerator"
initial-set="flowchart"/>

Attributes

  • surfaceId:string Required. The ID of the surface to which to attach the palette.
  • shapeLibrary:ShapeLibraryImpl Your shape library
  • dragSize:Size Optional size to set on elements when they are being dragged. If this is omitted, the derived iconSize will be used.
  • iconSize:Size Optional, defaults to 150x100 pixels. This is the size to use for each icon. It will also be used for dragSize if that is not separately specified.
  • fill:string Optional, defaults to "#FFFFFF". Fill color to use for icons.
  • outline:string Optional, defaults to "#000000". Color to use for icon outline.
  • selectAfterDrop:boolean Optional, defaults to true. Instructs the palette to set a newly dropped vertex as the Toolkit's selection.
  • canvasStrokeWidth:number Optional, defaults to 2. The stroke width to use when rendering dropped vertices on the canvas.
  • paletteStrokeWidth:number Optional, defaults to 1. The stroke width to use when rendering icons in the palette.
  • dataGenerator:DataGeneratorFunction Optional. Provide one of these if you wish to be able to set initial data for some icon that is about to be dragged on to the canvas.
  • initialSet If your shape library has multiple sets but when the palette is first rendered you want to specify a single set to show, set this value.