Skip to content

Commit

Permalink
feat(examples): add libavoid orthogonal routing demo (#2626)
Browse files Browse the repository at this point in the history
  • Loading branch information
kumilingus authored Apr 24, 2024
1 parent e842ea4 commit 8369b04
Show file tree
Hide file tree
Showing 12 changed files with 1,243 additions and 188 deletions.
3 changes: 3 additions & 0 deletions examples/libavoid/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build/
dist/
node_modules/
24 changes: 24 additions & 0 deletions examples/libavoid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# JointJS Libavoid Standalone Routing Demo

## Setup

Use Yarn to run this demo.

You need to build *JointJS* first. Navigate to the root folder and run:
```bash
yarn install
yarn run build
```

Navigate to this directory, then run:
```bash
yarn start
```

## License

The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE).

Copyright © 2013-2024 client IO

The *Libavoid-js* library is licensed under the [LGPL-2.1 license][https://github.com/Aksem/libavoid-js?tab=LGPL-2.1-1-ov-file#readme].
17 changes: 17 additions & 0 deletions examples/libavoid/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="The JointJS ELK Layered Layout demo serves as a template to help bring your idea to life in no time.">
<title>ELK Layered Layout | JointJS</title>
<link rel="stylesheet" type="text/css" href="css/styles.css">
</head>
<body>
<div id="canvas" class="canvas"></div>

<!-- Application files: -->
<script src="bundle.js"></script>

</body>
</html>
4 changes: 4 additions & 0 deletions examples/libavoid/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import './styles.scss';
import { init } from './src/app';

init();
39 changes: 39 additions & 0 deletions examples/libavoid/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@joint/demo-libavoid-js",
"version": "4.0.2",
"main": "src/index.js",
"homepage": "https://jointjs.com",
"author": {
"name": "client IO",
"url": "https://client.io"
},
"license": "LGPL-2.1-or-later",
"private": true,
"installConfig": {
"hoistingLimits": "workspaces"
},
"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
},
"dependencies": {
"@joint/core": "workspace:^",
"libavoid-js": "0.4.0-beta.1"
},
"devDependencies": {
"copy-webpack-plugin": "5.1.1",
"css-loader": "3.5.3",
"file-loader": "6.0.0",
"sass": "1.26.8",
"sass-loader": "8.0.2",
"style-loader": "1.2.1",
"webpack": "^5.61.0",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.2.1"
},
"volta": {
"node": "16.18.1",
"npm": "8.19.2",
"yarn": "3.4.1"
}
}
235 changes: 235 additions & 0 deletions examples/libavoid/src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
import { linkTools, elementTools, dia, shapes, highlighters } from '@joint/core';
import { Node, Edge } from './shapes';
import ResizeTool from './resize-tool';
import { AvoidRouter } from './avoid-router';

// Avoid Docs
// https://www.adaptagrams.org/documentation/annotated.html

// There is a bug in JointJS, that does not allow you to use port
// ids that are numbers.

export const init = async () => {
await AvoidRouter.load();

const canvasEl = document.getElementById('canvas');

const cellNamespace = {
...shapes,
Node,
Edge,
};

const graph = new dia.Graph({}, { cellNamespace });
const paper = new dia.Paper({
model: graph,
cellViewNamespace: cellNamespace,
width: 1000,
height: 600,
gridSize: 10,
interactive: { linkMove: false },
linkPinning: false,
async: true,
frozen: true,
background: { color: '#F3F7F6' },
snapLinks: { radius: 30 },
overflow: true,
defaultConnector: {
name: 'straight',
args: {
cornerType: 'cubic',
cornerRadius: 4,
},
},
highlighting: {
default: {
name: 'mask',
options: {
padding: 2,
attrs: {
stroke: '#EA3C24',
strokeWidth: 2,
},
},
},
},
defaultLink: () => new Edge(),
validateConnection: (
sourceView,
sourceMagnet,
targetView,
targetMagnet,
end
) => {
const source = sourceView.model;
const target = targetView.model;
if (source.isLink() || target.isLink()) return false;
if (targetMagnet === sourceMagnet) return false;
if (end === 'target' ? targetMagnet : sourceMagnet) {
return true;
}
if (source === target) return false;
return end === 'target' ? !target.hasPorts() : !source.hasPorts();
},
});

const c1 = new Node({
position: { x: 100, y: 100 },
size: { width: 100, height: 100 },
ports: {
items: [
{
group: 'top',
id: 'port1',
},
{
group: 'top',
id: 'port2',
},
{
group: 'right',
id: 'port3',
},
{
group: 'left',
id: 'port4',
// TODO: we need to redefine the port on element resize
// The port is currently defined proportionally to the element size.
// args: {
// dy: 30
// }
},
],
},
});

const c2 = c1.clone().set({
position: { x: 300, y: 300 },
size: { width: 100, height: 100 },
});

const c3 = c1.clone().set({
position: { x: 500, y: 100 },
size: { width: 100, height: 100 },
});

const c4 = new Node({
position: { x: 100, y: 400 },
size: { width: 100, height: 100 },
});

const c5 = c4.clone().set({
position: { x: 500, y: 300 },
size: { width: 100, height: 100 },
});

const l1 = new Edge({
source: { id: c1.id, port: 'port4' },
target: { id: c2.id, port: 'port4' },
});

const l2 = new Edge({
source: { id: c2.id, port: 'port2' },
target: { id: c3.id, port: 'port4' },
});

const l3 = new Edge({
source: { id: c4.id },
target: { id: c5.id },
});

const l4 = new Edge({
source: { id: c5.id },
target: { id: c4.id },
});

graph.addCells([c1, c2, c3, c4, c5, l1, l2, l3, l4]);

canvasEl.appendChild(paper.el);

paper.unfreeze();
paper.fitToContent({
useModelGeometry: true,
padding: 100,
allowNewOrigin: 'any',
});

// Add tools to the elements.
graph.getElements().forEach((el) => addElementTools(el, paper));
graph.on('add', (cell) => {
if (cell.isLink()) return;
addElementTools(cell, paper);
});

function addElementTools(el, paper) {
const tools = [
new ResizeTool({
selector: 'body',
}),
new elementTools.Remove({
useModelGeometry: true,
x: -10,
y: -10,
}),
];
if (!el.hasPorts()) {
tools.push(
new elementTools.Connect({
useModelGeometry: true,
x: 'calc(w + 10)',
y: 'calc(h - 20)',
})
);
}

el.findView(paper).addTools(new dia.ToolsView({ tools }));
}

// Add tools to the links.
paper.on('link:mouseenter', (linkView) => {
linkView.addTools(
new dia.ToolsView({
tools: [
new linkTools.Remove(),
new linkTools.TargetArrowhead(),
],
})
);
});

paper.on('link:mouseleave', (linkView) => {
linkView.removeTools();
});

paper.on('blank:pointerdblclick', (evt, x, y) => {
const node = new Node({
position: { x: x - 50, y: y - 50 },
size: { width: 100, height: 100 },
});
graph.addCell(node);
});

// Add a class to the links when they are being interacted with.
// See `styles.css` for the styles.

paper.on('link:pointerdown', (linkView) => {
highlighters.addClass.add(linkView, 'line', 'active-link', {
className: 'active-link'
});
});

paper.on('link:pointerup', (linkView) => {
highlighters.addClass.remove(linkView);
});

// Start the Avoid Router.

const router = new AvoidRouter(graph, {
shapeBufferDistance: 20,
idealNudgingDistance: 10,
portOverflow: Node.PORT_RADIUS,
});

router.addGraphListeners();
router.routeAll();
};
Loading

0 comments on commit 8369b04

Please sign in to comment.