-
Notifications
You must be signed in to change notification settings - Fork 853
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(examples): add libavoid orthogonal routing demo (#2626)
- Loading branch information
1 parent
e842ea4
commit 8369b04
Showing
12 changed files
with
1,243 additions
and
188 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
build/ | ||
dist/ | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import './styles.scss'; | ||
import { init } from './src/app'; | ||
|
||
init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
}; |
Oops, something went wrong.