Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
b01e8a5
start
Geliogabalus Sep 2, 2026
a04e4a5
feat(joint-layout-elk): support hierarchical containers, ports and pe…
Geliogabalus Sep 7, 2026
6ea64c0
example(layout-elk): add containers, ports and width-restriction demo
Geliogabalus Sep 7, 2026
044ce02
docs(changeset): add 'new package' changeset for @joint/layout-elk
Geliogabalus Sep 7, 2026
43141df
up
Geliogabalus Sep 8, 2026
d9fceb4
port and portLabels wip
Geliogabalus Sep 8, 2026
d54a624
full types wip
Geliogabalus Sep 8, 2026
94494fa
estimate port label size
Geliogabalus Sep 8, 2026
4649672
refactor
Geliogabalus Sep 8, 2026
1851508
up
Geliogabalus Sep 8, 2026
3a10389
wip
Geliogabalus Sep 10, 2026
853dfcb
interactive wip
Geliogabalus Sep 10, 2026
268c5e9
refactor to function
Geliogabalus Sep 10, 2026
b21af6e
wip
Geliogabalus Sep 11, 2026
c5b638a
wip
Geliogabalus Sep 13, 2026
7e4d090
wip refactor
Geliogabalus Sep 16, 2026
3b7f125
fix
Geliogabalus Sep 16, 2026
9b2df31
update
Geliogabalus Sep 16, 2026
e2140cf
up
Geliogabalus Sep 17, 2026
f7ad46c
wip
Geliogabalus Sep 17, 2026
b1935a7
fixes
Geliogabalus Sep 21, 2026
86f521e
update
Geliogabalus Sep 21, 2026
b494e69
fixes
Geliogabalus Sep 21, 2026
974373c
clean up
Geliogabalus Sep 21, 2026
bc60853
port label fix
Geliogabalus Sep 21, 2026
3ecd28b
update
Geliogabalus Sep 21, 2026
d904418
updates
Geliogabalus Sep 22, 2026
32d8ded
link label attributes refactor
Geliogabalus Sep 22, 2026
52f4a60
update
Geliogabalus Sep 22, 2026
278e7b2
update
Geliogabalus Sep 23, 2026
4a456e1
update
Geliogabalus Sep 23, 2026
dd93756
up
Geliogabalus Sep 23, 2026
11afedc
wip
Geliogabalus Sep 24, 2026
4be9d85
update API
Geliogabalus Sep 25, 2026
32fa661
ports core revert
Geliogabalus Sep 25, 2026
db5137f
restyle
Geliogabalus Sep 28, 2026
71df982
reordering example wip
Geliogabalus Sep 29, 2026
41b106d
comment fixes
Geliogabalus Sep 29, 2026
6c0543f
tests fix
Geliogabalus Sep 29, 2026
140f7b0
to exportLink
Geliogabalus Sep 29, 2026
95dc392
cleaning comments and README
Geliogabalus Sep 30, 2026
7ae4f9f
renaming options
Geliogabalus Sep 30, 2026
f5c8063
default behaviour example
Geliogabalus Sep 30, 2026
c785c6f
update
Geliogabalus Oct 1, 2026
94e60ae
up
Geliogabalus Oct 1, 2026
caba681
fixes
Geliogabalus Oct 2, 2026
1b01267
fixes and updates
Geliogabalus Oct 2, 2026
b0494f8
updates
Geliogabalus Oct 5, 2026
e474c71
worker update
Geliogabalus Oct 5, 2026
462c2bb
optional graph
Geliogabalus Oct 5, 2026
6097811
fix
Geliogabalus Oct 5, 2026
36317fd
fix(layout-elk): apply laid out link labels by id, not by position in…
Geliogabalus Oct 6, 2026
5623464
fix(layout-elk): export elements with ports with FIXED_POS port const…
Geliogabalus Oct 6, 2026
3f4addd
fix(layout-elk): close the layout batch when an import callback throws
Geliogabalus Oct 6, 2026
9ef0fdf
feat(layout-elk): add `signal` option to abort a layout
Geliogabalus Oct 6, 2026
8d62218
perf(layout-elk): load main-thread ELK only when a layout runs on the…
Geliogabalus Oct 6, 2026
0021381
fix(layout-elk): fall back to the main thread only when the worker fa…
Geliogabalus Oct 6, 2026
630b5d1
feat(layout-elk): warn once when ELK falls back to the main thread
Geliogabalus Oct 6, 2026
600a5b7
feat(layout-elk): add `thread` option to choose where the default ELK…
Geliogabalus Oct 6, 2026
97cb60f
chore(layout-elk): set version to 4.3.0
Geliogabalus Oct 6, 2026
621114a
fix(examples): fix ELK examples
Geliogabalus Oct 6, 2026
1fa655c
feat(layout-elk)!: run ELK on the main thread by default, add createW…
Geliogabalus Oct 6, 2026
fc75f03
fix(examples): run ELK in a Web Worker with createWorkerElk()
Geliogabalus Oct 6, 2026
cddc7cf
comments fixes
Geliogabalus Oct 7, 2026
2e11128
cleaning examples
Geliogabalus Oct 8, 2026
9372f0c
fix(layout-elk): track the layouts actually posted to the ELK worker
Geliogabalus Oct 8, 2026
a1f7406
fix(layout-elk): drop a port label when exportPortLabel returns false
Geliogabalus Oct 8, 2026
673c8d0
fix(layout-elk): reject an aborted layout with a `null` abort reason …
Geliogabalus Oct 8, 2026
67d44c3
fix(dia.Element): type portProp(portId) and portProp(portId, object, …
Geliogabalus Oct 8, 2026
f12a73a
chore: add @joint/layout-elk and its examples to yarn.lock
Geliogabalus Oct 8, 2026
d0625d4
fix(layout-elk): read resolved link labels through the protected getC…
Geliogabalus Oct 8, 2026
731ab17
up
Geliogabalus Oct 8, 2026
bae803b
fix(layout-elk): keep ELK ids unique, and lay out a container without…
Geliogabalus Oct 8, 2026
248c765
fix(examples): drop the containers-ports example's stale link label `…
Geliogabalus Oct 8, 2026
f7279be
docs(layout-elk): document loading elkjs before the UMD build
Geliogabalus Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/layout-elk-new-package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@joint/layout-elk": minor
---

new package - automatic layout for JointJS graphs using the Eclipse Layout Kernel (ELK), including layout of embedded elements as containers and of element ports
5 changes: 5 additions & 0 deletions .changeset/port-label-position-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@joint/core": patch
---

dia.Element - fix `PortLabelPositionType` type to use `PortLabelPositionJSON` for a port label's position
5 changes: 5 additions & 0 deletions .changeset/port-prop-overloads.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@joint/core": patch
---

dia.Element - fix types to allow `portProp(portId)` and `portProp(portId, object, opt)`
3 changes: 3 additions & 0 deletions examples/layout-elk-containers-ports-ts/.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/layout-elk-containers-ports-ts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# JointJS ELK Containers & Ports Demo

A fixed (non-random) web platform reference architecture laid out automatically with `@joint/layout-elk`: nested containers ("Client Layer" > "Edge", "Core Services" > "Data Layer", "Observability") grouping services that connect through ports, plus a couple of links connecting containers directly - including one that crosses from one container into another. Styled with Material Design, via JointJS's theme mechanism and CSS.

## 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-2026 client IO
25 changes: 25 additions & 0 deletions examples/layout-elk-containers-ports-ts/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!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="An automatic layout demo of a fixed graph with containers and ports, using JointJS and ELK.">
<title>ELK Containers & Ports Layout | JointJS</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
</head>

<body>
<div class="toolbar">
<span id="zoom-out" class="toolbar-button">Zoom Out</span>
<span id="zoom-in" class="toolbar-button">Zoom In</span>
</div>
<div id="canvas" class="canvas"></div>
<script src="dist/bundle.js"></script>

</body>

</html>
39 changes: 39 additions & 0 deletions examples/layout-elk-containers-ports-ts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@joint/demo-layout-elk-containers-ports-ts",
"version": "4.3.1",
"description": "JointJS - ELK Layout Containers & Ports Demo",
"main": "dist/bundle.js",
"homepage": "https://jointjs.com",
"author": {
"name": "client IO",
"url": "https://client.io"
},
"license": "MPL-2.0",
"private": true,
"installConfig": {
"hoistingLimits": "workspaces"
},
"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
},
"dependencies": {
"@joint/core": "workspace:^",
"@joint/layout-elk": "workspace:^"
},
"devDependencies": {
"css-loader": "3.5.3",
"sass-loader": "8.0.2",
"style-loader": "1.2.1",
"ts-loader": "^9.2.5",
"typescript": "5.8.2",
"webpack": "5.98.0",
"webpack-cli": "6.0.1",
"webpack-dev-server": "5.2.0"
},
"volta": {
"node": "22.14.0",
"npm": "11.2.0",
"yarn": "4.18.0"
}
}
208 changes: 208 additions & 0 deletions examples/layout-elk-containers-ports-ts/src/example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import { dia } from '@joint/core';

// A fixed (non-random) system diagram: three top-level containers, two of
// them with a nested container of their own, grouping eight services that
// communicate over ports - plus a couple of links that connect two
// containers directly, rather than a pair of ports, including one that
// crosses container boundaries. A recognizable, if simplified, web platform
// reference architecture: a client layer talking through an edge (load
// balancer + API gateway) to core services (auth, guarding a data layer of
// cache + database), with logs/metrics/analytics flowing to observability.
// Every plain `example.Service` has exactly one 'in' and one 'out' port; the
// four "hub" services (Load Balancer, API Gateway, Auth Service, Monitoring)
// are `example.HubService` instead, with a custom number of ports and ELK's
// `FIXED_SIDE` port constraint, so it can reorder them to minimize crossings
// (see `index.ts`).
export const graphJSON: dia.Graph.JSON = {
cells: [
// Containers
{
id: 'frontend',
type: 'example.Container',
attrs: { label: { text: 'Client Layer' } }
},
{
id: 'edge',
type: 'example.Container',
parent: 'frontend',
attrs: { label: { text: 'Edge' } }
},
{
id: 'backend',
type: 'example.Container',
attrs: { label: { text: 'Core Services' } }
},
{
id: 'storage',
type: 'example.Container',
parent: 'backend',
attrs: { label: { text: 'Data Layer' } }
},
{
id: 'observability',
type: 'example.Container',
attrs: { label: { text: 'Observability' } }
},

// Client Layer
{
id: 'webui',
type: 'example.Service',
parent: 'frontend',
attrs: { label: { text: 'Web App' } }
},
{
id: 'mobileui',
type: 'example.Service',
parent: 'frontend',
attrs: { label: { text: 'Mobile App' } }
},
{
id: 'lb',
type: 'example.HubService',
parent: 'edge',
size: { width: 130, height: 80 },
attrs: { label: { text: 'Load Balancer' } },
ports: {
items: [
{ id: 'in1', group: 'in', attrs: { text: { text: 'in1' } } },
{ id: 'in2', group: 'in', attrs: { text: { text: 'in2' } } },
{ id: 'out', group: 'out', attrs: { text: { text: 'out' } } }
]
}
},
{
id: 'gateway',
type: 'example.HubService',
parent: 'edge',
size: { width: 130, height: 80 },
attrs: { label: { text: 'API Gateway' } },
ports: {
items: [
{ id: 'in', group: 'in', attrs: { text: { text: 'in' } } },
{ id: 'out1', group: 'out', attrs: { text: { text: 'out1' } } },
{ id: 'out2', group: 'out', attrs: { text: { text: 'out2' } } }
]
}
},

// Core Services
{
id: 'auth',
type: 'example.HubService',
parent: 'backend',
size: { width: 130, height: 80 },
attrs: { label: { text: 'Auth Service' } },
ports: {
items: [
{ id: 'in', group: 'in', attrs: { text: { text: 'in' } } },
{ id: 'out1', group: 'out', attrs: { text: { text: 'out1' } } },
{ id: 'out2', group: 'out', attrs: { text: { text: 'out2' } } }
]
}
},
{
id: 'cache',
type: 'example.Service',
parent: 'storage',
attrs: { label: { text: 'Redis Cache' } }
},
{
id: 'db',
type: 'example.Service',
parent: 'storage',
attrs: { label: { text: 'PostgreSQL' } }
},

// Observability
{
id: 'monitoring',
type: 'example.HubService',
parent: 'observability',
size: { width: 130, height: 80 },
attrs: { label: { text: 'Monitoring' } },
ports: {
items: [
{ id: 'in1', group: 'in', attrs: { text: { text: 'in1' } } },
{ id: 'in2', group: 'in', attrs: { text: { text: 'in2' } } }
]
}
},

// Links
{
id: 'l1',
type: 'example.InteractionLink',
source: { id: 'webui', port: 'out' },
target: { id: 'lb', port: 'in1' },
labels: [{ attrs: { text: { text: 'request' } } }]
},
{
id: 'l2',
type: 'example.InteractionLink',
source: { id: 'mobileui', port: 'out' },
target: { id: 'lb', port: 'in2' },
labels: [{ attrs: { text: { text: 'request' } } }]
},
{
id: 'l3',
type: 'example.InteractionLink',
source: { id: 'lb', port: 'out' },
target: { id: 'gateway', port: 'in' },
labels: [{ attrs: { text: { text: 'route' } } }]
},
{
id: 'l4',
type: 'example.InteractionLink',
source: { id: 'gateway', port: 'out1' },
target: { id: 'auth', port: 'in' },
labels: [{ attrs: { text: { text: 'authenticate' } } }]
},
{
id: 'l5',
type: 'example.InteractionLink',
source: { id: 'gateway', port: 'out2' },
target: { id: 'monitoring', port: 'in1' },
labels: [{ attrs: { text: { text: 'metrics' } } }]
},
{
id: 'l6',
type: 'example.InteractionLink',
source: { id: 'auth', port: 'out1' },
target: { id: 'cache', port: 'in' },
labels: [{ attrs: { text: { text: 'lookup' } } }]
},
{
id: 'l7',
type: 'example.InteractionLink',
source: { id: 'auth', port: 'out2' },
target: { id: 'monitoring', port: 'in2' },
labels: [{ attrs: { text: { text: 'logs' } } }]
},
{
id: 'l8',
type: 'example.InteractionLink',
source: { id: 'cache', port: 'out' },
target: { id: 'db', port: 'in' },
labels: [{ attrs: { text: { text: 'query' } } }]
},

// Container-to-container links - connected to a `example.Container` cell
// itself rather than to one of its ports, aggregating what the individual
// service-to-service links above already carry.
{
id: 'l9',
type: 'example.InteractionLink',
source: { id: 'backend' },
target: { id: 'observability' },
labels: [{ attrs: { text: { text: 'metrics' } } }]
},
{
id: 'l10',
type: 'example.InteractionLink',
source: { id: 'frontend' },
target: { id: 'observability' },
labels: [{ attrs: { text: { text: 'analytics' } } }]
}
]
};
Loading
Loading