const { setTheme, dia, shapes, ui, util, linkTools } = joint;
// For modules:
// import { setTheme, dia, shapes, ui, util, linkTools } from '@clientio/rappid';
// Set a theme (optional - use a theme or custom-style)
// ----------------------------------------------------
setTheme('dark');
//setTheme('material');
//setTheme('modern');
//setTheme('default');
// Graph
// -----
const graph = new dia.Graph({}, { cellNamespace: shapes });
// Paper & PaperScroller
// ---------------------
const paper = new dia.Paper({
model: graph, // Set graph as the model for paper
cellViewNamespace: shapes,
width: 1000,
height: 1000,
gridSize: 10,
drawGrid: true,
defaultLink: (elementView, magnet) => {
return new shapes.standard.Link({
attrs: { line: { stroke: '#fbf5d0' }}
});
},
async: true,
sorting: dia.Paper.sorting.APPROX,
interactive: { linkMove: false },
snapLinks: { radius: 70 },
defaultConnectionPoint: { name: 'boundary' }
});
const paperScroller = new ui.PaperScroller({
paper,
autoResizePaper: true,
cursor: 'grab'
});
document.querySelector('.paper-container').appendChild(paperScroller.el);
paperScroller.render().center();
paper.on('blank:pointerdown', (evt) => {
// Start panning the paper on mousedown
paperScroller.startPanning(evt);
});
// Custom Shape
// ------------
const MyShape = dia.Element.define('myApp.MyShape', {
attrs: {
body: {
width: 'calc(w)',
height: 'calc(h)',
strokeWidth: 2,
stroke: '#000000',
fill: '#FFFFFF'
},
label: {
x: 'calc(w/2)',
y: 'calc(h/2)',
textAnchor: 'middle',
textVerticalAnchor: 'middle',
fontSize: 14,
fill: '#333333'
},
root: {
magnet: false // Disable the possibility to connect the body of our shape. Only ports can be connected.
}
},
level: 1,
ports: {
groups: {
'in': {
markup: util.svg``,
z: -1,
attrs: {
portBody: {
r: 12,
magnet: true,
fill: '#00879b'
}
},
position: { name: 'left' },
label: { position: { name: 'left' }}
},
'out': {
markup: util.svg``,
z: -1,
attrs: {
portBody: {
r: 12,
magnet: true,
fill: '#00879b'
}
},
position: { name: 'right' },
label: { position: { name: 'right' }}
}
}
}
}, {
markup: util.svg`
`
});
// Stencil
// -------
const stencil = new ui.Stencil({
paper: paperScroller,
scaleClones: true,
width: 240,
groups: {
myShapesGroup1: { index: 1, label: ' My Shapes 1' },
myShapesGroup2: { index: 2, label: ' My Shapes 2' }
},
dropAnimation: true,
groupsToggleButtons: true,
search: {
'*': ['type', 'attrs/label/text']
},
layout: true // Use the default 2 columns layout with auto-resize
});
document.querySelector('.stencil-container').appendChild(stencil.el);
stencil.render().load({
myShapesGroup1: [{
type: 'standard.Rectangle'
}, {
type: 'standard.Ellipse'
}],
myShapesGroup2: [{
type: 'standard.Cylinder'
}, {
type: 'myApp.MyShape',
attrs: { label: { text: 'Shape' }},
ports: { items: [{ group: 'in' }, { group: 'out' }, { group: 'out' }] }
}]
});
// Inspector
// --------
paper.on('element:pointerclick', (elementView) => {
ui.Inspector.create('.inspector-container', {
cell: elementView.model,
inputs: {
'attrs/label/text': {
type: 'text',
label: 'Label',
group: 'basic',
index: 1
},
level: {
type: 'range',
min: 1,
max: 10,
unit: 'x',
defaultValue: 6,
label: 'Level',
group: 'advanced',
index: 2
}
},
groups: {
basic: {
label: 'Basic',
index: 1
},
advanced: {
label: 'Advanced',
index: 2
}
}
});
});
paper.on('link:pointerdown blank:pointerdown', () => {
ui.Inspector.close();
});
// Halo
// ----
paper.on('element:pointerclick', (elementView) => {
const handles = [{
name: 'remove',
position: 'nw',
events: { pointerdown: 'removeElement' }
}, {
name: 'myCustomAction',
position: 'ne',
icon: 'data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7'
}];
if (!elementView.model.hasPorts()) {
// Only shapes without ports will have the "link" handle in the Halo control panel. Shapes with ports can be connected by "dragging" ports.
handles.push({
name: 'link',
position: 'e',
events: { pointerdown: 'startLinking', pointermove: 'doLink', pointerup: 'stopLinking' }
});
}
const halo = new ui.Halo({
cellView: elementView,
handles
}).render();
halo.on('action:myCustomAction:pointerdown', (evt) => {
alert('My Control Button Clicked!');
});
});
// Link Tools
// ----------
paper.on('link:pointerclick', (linkView) => {
paper.removeTools();
const toolsView = new dia.ToolsView({
tools: [
new linkTools.Vertices(),
new linkTools.SourceArrowhead(),
new linkTools.TargetArrowhead(),
new linkTools.Segments,
new linkTools.Remove({ offset: -20, distance: 40 })
]
});
linkView.addTools(toolsView);
});
paper.on('blank:pointerdown', (evt) => {
paper.removeTools();
});
// Toolbar
// -------
const toolbar = new ui.Toolbar({
groups: {
clear: { index: 1 },
zoom: { index: 2 }
},
tools: [
{ type: 'button', name: 'clear', group: 'clear', text: 'Clear Diagram' },
{ type: 'zoom-out', name: 'zoom-out', group: 'zoom' },
{ type: 'zoom-in', name: 'zoom-in', group: 'zoom' }
],
references: {
paperScroller // built in zoom-in/zoom-out control types require access to paperScroller instance
}
});
toolbar.on({
'clear:pointerclick': () => graph.clear()
});
document.querySelector('.toolbar-container').appendChild(toolbar.el);
toolbar.render();
// Working With Diagrams Programmatically
// --------------------------------------
// Add new element to the graph.
const myShape = new MyShape({
size: { width: 100, height: 100 },
position: { x: 50, y: 50 },
attrs: { label: { text: 'My Shape' }},
level: 3,
ports: { items: [{ id: 'in1', group: 'in' }, { group: 'out', id: 'out1' }] }
});
graph.addCell(myShape);
// Get element from the graph and change its properties.
console.log(myShape === graph.getElements()[0]);
myShape.prop('attrs/label/text', 'My Updated Shape');
myShape.prop('size/width', 150);
myShape.prop('level', 2);
myShape.prop('attrs/body/fill', '#80eaff');
// Create a clone of an element.
const myShape2 = myShape.clone();
myShape2.translate(400, 0);
graph.addCell(myShape2);
// Create a link that connects two elements.
const myLink = new shapes.standard.Link({
attrs: { line: { stroke: '#fbf5d0' }},
source: { id: myShape.id, port: 'out1' },
target: { id: myShape2.id, port: 'in1' }
});
graph.addCell(myLink);
// React on changes in the graph.
graph.on('change add remove', () => {
const diagramJSONString = JSON.stringify(graph.toJSON());
console.log('Diagram JSON', diagramJSONString);
});
graph.on('change:level', (cell, level) => {
const color = (level > 8) ? '#ff9580' : '#ffffff';
cell.prop('attrs/body/fill', color);
});