❮ Back to Gallery
ELK Layered Graph Layout
This example shows how to use The Eclipse Layout Kernel (ELK) with Graph. ELK is a powerful layout engine with many different types of graph layouts available. Check out the ELK Demonstrators page to learn more.
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
- Data
/* eslint-disable @typescript-eslint/naming-convention */
import React, { useCallback, useMemo } from 'react'
import { VisSingleContainer, VisGraph } from '@unovis/react'
import { GraphLayoutType, GraphNodeShape } from '@unovis/ts'
import { data, NodeDatum, LinkDatum, panels } from './data'
import './styles.css'
export default function ForceLayoutGraph (): JSX.Element {
const layoutElkSettings = {
'layered.crossingMinimization.forceNodeModelOrder': 'true',
'elk.direction': 'RIGHT',
'elk.padding': '[top=30.0,left=0.0,bottom=30.0,right=0.0]',
'spacing.nodeNodeBetweenLayers': '250',
}
return (
<div className='chart'>
<VisSingleContainer data={data} height={'60vh'}>
<VisGraph<NodeDatum, LinkDatum>
nodeShape={GraphNodeShape.Square}
nodeStrokeWidth={1.5}
nodeLabel={useCallback((n: NodeDatum) => n.id, [])}
layoutType={GraphLayoutType.Elk}
layoutElkNodeGroups={useMemo(() => [
(d: NodeDatum): string | null => d.group ?? null,
(d: NodeDatum): string | null => d.subGroup ?? null,
], [])}
layoutElkSettings={layoutElkSettings}
panels={panels}
disableZoom
/>
</VisSingleContainer>
</div>
)
}
elk-layered-graph.html
<div class="chart">
<vis-single-container [data]="data" height="60vh">
<vis-graph
[layoutType]="layoutType"
[nodeShape]="nodeShape"
[nodeStrokeWidth]="nodeStrokeWidth"
[nodeLabel]="nodeLabel"
[layoutElkNodeGroups]="layoutElkNodeGroups"
[layoutElkSettings]="layoutElkSettings"
[panels]="panels"
[disableZoom]="false"
></vis-graph>
</vis-single-container>
</div>
elk-layered-graph.component.ts
import { Component } from '@angular/core'
import { GraphLayoutType, GraphNodeShape } from '@unovis/ts'
import { data, NodeDatum, panels } from './data'
@Component({
selector: 'elk-graph',
templateUrl: './elk-layered-graph.component.html',
styleUrls: ['./styles.css'],
})
export class ElkLayeredGraphComponent {
data = data
layoutType = GraphLayoutType.Elk
nodeShape = GraphNodeShape.Square
nodeStrokeWidth = 1.5
nodeLabel = (n: NodeDatum): string => n.id
panels = panels
layoutElkNodeGroups = [
(d: NodeDatum): string | null => d.group ?? null,
(d: NodeDatum): string | null => d.subGroup ?? null,
]
layoutElkSettings = {
'layered.crossingMinimization.forceNodeModelOrder': 'true',
'elk.direction': 'RIGHT',
'elk.padding': '[top=30.0,left=10.0,bottom=30.0,right=10.0]',
'nodePlacement.strategy': 'SIMPLE',
}
}
elk-layered-graph.module.ts
import { NgModule } from '@angular/core'
import { VisSingleContainerModule, VisGraphModule } from '@unovis/angular'
import { ElkLayeredGraphComponent } from './elk-layered-graph.component'
@NgModule({
imports: [VisSingleContainerModule, VisGraphModule],
declarations: [ElkLayeredGraphComponent],
exports: [ElkLayeredGraphComponent],
})
export class ElkLayeredGraphModule { }
<script lang='ts'>
import { VisSingleContainer, VisGraph } from '@unovis/svelte'
import { GraphLayoutType, GraphNodeShape } from '@unovis/ts'
import { data, NodeDatum, LinkDatum, panels } from './data'
const layoutElkSettings = {
'layered.crossingMinimization.forceNodeModelOrder': 'true',
'elk.direction': 'RIGHT',
'elk.padding': '[top=30.0,left=10.0,bottom=30.0,right=10.0]',
'nodePlacement.strategy': 'SIMPLE',
}
const nodeShape = GraphNodeShape.Square
const nodeStrokeWidth = 1.5
const nodeLabel = (n: NodeDatum) => n.id
const layoutType = GraphLayoutType.Elk
const layoutElkNodeGroups = [
(d: NodeDatum) => d.group ?? null,
(d: NodeDatum) => d.subGroup ?? null,
]
</script>
<div class="chart">
<VisSingleContainer {data} height={'60vh'}>
<VisGraph
{nodeShape}
{nodeStrokeWidth}
{nodeLabel}
{layoutType}
{layoutElkNodeGroups}
{layoutElkSettings}
{panels}
disableZoom
/>
</VisSingleContainer>
</div>
<style>
@font-face {
font-family: 'Font Awesome 6 Free';
src: url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/webfonts/fa-solid-900.woff2)
format('woff2');
}
.chart {
--vis-graph-icon-font-family: 'Font Awesome 6 Free';
}
</style>
<script setup lang="ts">
import { VisSingleContainer, VisGraph } from '@unovis/vue'
import { GraphLayoutType, GraphNodeShape } from '@unovis/ts'
import { data, NodeDatum, LinkDatum, panels } from './data'
const layoutElkSettings = {
'layered.crossingMinimization.forceNodeModelOrder': 'true',
'elk.direction': 'RIGHT',
'elk.padding': '[top=30.0,left=10.0,bottom=30.0,right=10.0]',
'nodePlacement.strategy': 'SIMPLE',
}
const nodeShape = GraphNodeShape.Square
const nodeStrokeWidth = 1.5
const nodeLabel = (n: NodeDatum) => n.id
const layoutType = GraphLayoutType.Elk
const layoutElkNodeGroups = [
(d: NodeDatum) => d.group ?? null,
(d: NodeDatum) => d.subGroup ?? null,
]
</script>
<template>
<div class="chart">
<VisSingleContainer :data="data" height="60vh">
<VisGraph v-bind="{
nodeShape,
nodeStrokeWidth,
nodeLabel,
layoutType,
layoutElkNodeGroups,
layoutElkSettings,
panels
}" disableZoom />
</VisSingleContainer>
</div>
</template>
<style>
@font-face {
font-family: 'Font Awesome 6 Free';
src: url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/webfonts/fa-solid-900.woff2) format('woff2');
}
.chart {
--vis-graph-icon-font-family: 'Font Awesome 6 Free';
}
</style>
import { JSX } from 'solid-js'
import { GraphLayoutType, GraphNodeShape } from '@unovis/ts'
import { VisGraph, VisSingleContainer } from '@unovis/solid'
import './styles.css'
import { data, NodeDatum, panels } from './data'
const ElkLayerdGraph = (): JSX.Element => {
const layoutElkSettings = {
'layered.crossingMinimization.forceNodeModelOrder': 'true',
'elk.direction': 'RIGHT',
'elk.padding': '[top=30.0,left=10.0,bottom=30.0,right=10.0]',
'nodePlacement.strategy': 'SIMPLE',
}
const nodeShape = GraphNodeShape.Square
const nodeStrokeWidth = 1.5
const nodeLabel = (n: NodeDatum) => n.id
const layoutType = GraphLayoutType.Elk
const layoutElkNodeGroups = [
(d: NodeDatum) => d.group ?? null,
(d: NodeDatum) => d.subGroup ?? null,
]
return (
<div class="chart">
<VisSingleContainer data={data} height="50dvh">
<VisGraph
nodeShape={nodeShape}
nodeStrokeWidth={nodeStrokeWidth}
nodeLabel={nodeLabel}
layoutType={layoutType}
layoutElkNodeGroups={layoutElkNodeGroups}
layoutElkSettings={layoutElkSettings}
panels={panels}
disableZoom
/>
</VisSingleContainer>
</div>
)
}
export default ElkLayerdGraph
import { SingleContainer, Graph, GraphLayoutType, GraphNodeShape } from '@unovis/ts'
import { data, NodeDatum, LinkDatum, panels } from './data'
import './styles.css'
const layoutElkSettings = {
'layered.crossingMinimization.forceNodeModelOrder': 'true',
'elk.direction': 'RIGHT',
'elk.padding': '[top=30.0,left=10.0,bottom=30.0,right=10.0]',
'nodePlacement.strategy': 'SIMPLE',
}
const container = document.getElementById('vis-container')
container.classList.add('chart')
const chart = new SingleContainer(container, {
component: new Graph<NodeDatum, LinkDatum>({
nodeShape: GraphNodeShape.Square,
nodeStrokeWidth: 1.5,
nodeLabel: (n: NodeDatum) => n.id,
layoutType: GraphLayoutType.Elk,
layoutElkSettings: layoutElkSettings,
layoutElkNodeGroups: [
(d: NodeDatum): string | null => d.group ?? null,
(d: NodeDatum): string | null => d.subGroup ?? null,
],
panels: panels,
disableZoom: true,
}),
height: '60vh',
}, data)
export type NodeDatum = {
id: string;
group?: string;
subGroup?: string;
shape?: string;
}
export type LinkDatum = {
source: string;
target: string;
}
export const data = {
nodes: [
{ id: 'vpc', icon: '' },
{ id: '192.168.0.0/25', group: 'us-east-2a', subGroup: 'subnets', icon: '' },
{ id: '192.168.3.192/26', group: 'us-east-2a', subGroup: 'subnets', icon: '' },
{ id: '192.8.3.191/33', group: 'us-east-2a', subGroup: 'subnets', icon: '' },
{ id: 'master-0', group: 'us-east-2a', subGroup: 'nodes', icon: '' },
{ id: 'workload-name', group: 'us-east-2a', subGroup: 'nodes', icon: '' },
],
links: [
{ source: 'vpc', target: '192.168.0.0/25' },
{ source: 'vpc', target: '192.168.3.192/26' },
{ source: 'vpc', target: '192.8.3.191/33' },
{ source: '192.168.0.0/25', target: 'master-0' },
{ source: '192.168.3.192/26', target: 'master-0' },
{ source: '192.8.3.191/33', target: 'workload-name' },
],
}
export const panels = [
{
nodes: ['192.168.0.0/25', '192.168.3.192/26', '192.8.3.191/33', 'master-0', 'workload-name'],
label: 'us-east-2a',
dashedOutline: true,
padding: { top: 45, right: 30, bottom: 30, left: 30 },
},
{
nodes: ['192.168.0.0/25', '192.168.3.192/26', '192.8.3.191/33'],
label: 'subnets',
padding: { top: 5 },
},
{
nodes: ['master-0', 'workload-name'],
label: 'workload',
padding: { top: 5 },
},
]