Appearance
Sequential Layout
This example shows how to use the layer
option in the sequential layout, which allows to choose on which layer each node will be placed in the sequence.
ts
import Ogma, { NodeId, SequentialLayoutOptions } from '@linkurious/ogma';
import './styles.css';
const ogma = new Ogma({
container: 'graph-container',
options: { interactions: { drag: { enabled: false } } }
});
const defaultLayoutOptions: SequentialLayoutOptions = {
direction: 'TB', // Direction of the layout. Can be TB, BT, LR, or RL,
// where T = top, B = bottom, L = left, and R = right.
duration: 300, // Duration of the animation
nodeDistance: 15, // Number of pixels that separate nodes horizontally in the layout.
levelDistance: 50 // Number of pixels between each layer in the layout.
};
const runLayout = (options: SequentialLayoutOptions) =>
ogma.layouts.sequential({
...options,
locate: { easing: 'linear', duration: 300, padding: 50 }
});
const graph = await Ogma.parse.jsonFromUrl('data-flow.json');
await ogma.setGraph(graph);
await ogma.view.locateGraph();
await runLayout(defaultLayoutOptions);
const form = document.getElementById('wrapper') as HTMLFormElement;
form.addEventListener('change', () => requestAnimationFrame(onChange));
const onChange = () => {
const mode = Number(
Array.prototype.filter.call(form['layering'], input => {
return input.checked;
})[0].value
);
const modes = {
// you can mix layering and roots/sinks definitions
1: { Concept: 0, Table: 'sink' },
// or control the layer by layer as well
2: {
Concept: 0,
Subject: 1,
Area: 2,
DataElement: 3,
DataOwner: 4,
DataSteward: 5,
Column: 6,
Table: 7,
DQMetric: 8,
Database: 9,
DQDimension: 10,
DataPolicy: 11,
DataPrinciple: 12
}
};
ogma.getNodes().fillData('layer', null);
let sinks: NodeId[] = [];
// check if it's a supported mode
if (mode in modes) {
const customLogic = modes[mode];
// pick the sinks first
sinks = ogma
.getNodes()
.filter(node => {
const category = node.getData('categories')[0];
return customLogic[category] === 'sink';
})
.getId();
// now set the custom layering
ogma.getNodes().forEach(node => {
const category = node.getData('categories')[0];
const layer = customLogic[category];
if (typeof layer === 'number') {
// save the layer in the node data
node.setData('layer', layer);
}
});
}
// create fresh new options
const newOptions: SequentialLayoutOptions = { ...defaultLayoutOptions };
// save the sinks in the layout options
newOptions.sinks = sinks;
runLayout(newOptions);
};
html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<div id="graph-container"></div>
<form id="wrapper" class="control-bar">
<p>How to order the sequence:</p>
<label
><input type="radio" name="layering" checked value="0" /> Auto</label
>
<label
><input type="radio" name="layering" value="2" /> One color per
layer</label
>
<label
><input type="radio" name="layering" value="1" />
<span class="concept"></span> Concept →
<span class="table"></span> Table</label
>
</form>
<script type="module" src="index.ts"></script>
</body>
</html>
css
:root {
--base-font-family: 'IBM Plex Sans', Arial, Helvetica, sans-serif;
font-family: var(--base-font-family);
}
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: 0;
overflow: hidden;
}
#wrapper {
position: absolute;
top: 10px;
right: 10px;
z-index: 400;
background: white;
padding: 10px;
}
.control-bar {
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
border-radius: 4px;
}
.control-bar label {
display: block;
}
.concept {
height: 10px;
width: 10px;
background-color: #2ca02c;
border-radius: 50%;
display: inline-block;
}
.table {
height: 10px;
width: 10px;
background-color: #ff9896;
border-radius: 50%;
display: inline-block;
}
json
{
"nodes": [
{
"id": 0,
"attributes": {
"x": 2995,
"y": 300,
"color": "#2ca02c",
"radius": 5,
"shape": "circle",
"text": "Customer Portfolio"
},
"data": {
"categories": [
"Concept"
],
"properties": {
"name": "Customer Portfolio",
"definition": "A grouping of financial assets such as stocks, bonds and cash equivalents, as well as their mutual, exchange-traded and closed-fund counterparts. Portfolios are held directly by investors and/or managed by financial professionals.",
"id": 4
}
},
"x": 421.66666666666674,
"y": 0,
"r": 8.889887252841921,
"layer": 0,
"sink": false
},
{
"id": 1,
"attributes": {
"x": 2667.5,
"y": 200,
"color": "#ff7f0e",
"radius": 5,
"shape": "circle",
"text": "Customer"
},
"data": {
"categories": [
"Subject Area"
],
"properties": {
"name": "Customer"
}
},
"x": 337.33333333333337,
"y": 99.47145877378435,
"r": 7.015674871145073,
"sink": false
},
{
"id": 2,
"attributes": {
"x": 3127.5,
"y": 250,
"color": "#1f77b4",
"radius": 5,
"shape": "circle",
"text": "Portfolio Code"
},
"data": {
"categories": [
"DataElement"
],
"properties": {
"id": 9,
"label": "Portfolio Code"
}
},
"x": 506,
"y": 99.47145877378435,
"r": 5.461372976784961,
"sink": false
},
{
"id": 3,
"attributes": {
"x": 2867.5,
"y": 250,
"color": "#1f77b4",
"radius": 5,
"shape": "circle",
"text": "Portfolio Short Name"
},
"data": {
"categories": [
"DataElement"
],
"properties": {
"id": 8,
"label": "Portfolio Short Name"
}
},
"x": 463.8333333333333,
"y": 99.47145877378435,
"r": 10.645027362934385,
"sink": false
},
{
"id": 4,
"attributes": {
"x": 300,
"y": 200,
"color": "#17becf",
"radius": 5,
"shape": "circle",
"text": null
},
"data": {
"categories": [
"DataOwner"
],
"properties": {
"full_name": "David Jones",
"id": 1
}
},
"x": 674.6666666666666,
"y": 99.47145877378435,
"r": 4.378711202635261,
"sink": false
},
{
"id": 5,
"attributes": {
"x": 365,
"y": 250,
"color": "#2ca02c",
"radius": 5,
"shape": "circle",
"text": "Trader"
},
"data": {
"categories": [
"Concept"
],
"properties": {
"name": "Trader",
"definition": "An individual who engages in the transfer of financial assets in any financial market, either for themselves, or on behalf of a someone else. The main difference between a trader and an investor is the duration for which the person holds the asset. Investors tend to have a longer term time horizon, whereas traders tend to hold assets for shorter periods of time in order to capitalize on short-term trends.",
"id": 5
}
},
"x": 0,
"y": 0,
"r": 9.551798628830197,
"layer": 0,
"sink": false
},
{
"id": 6,
"attributes": {
"x": 310,
"y": 250,
"color": "#2ca02c",
"radius": 5,
"shape": "circle",
"text": "Investment"
},
"data": {
"categories": [
"Concept"
],
"properties": {
"name": "Investment",
"definition": "An asset or item that is purchased with the hope that it will generate income or appreciate in the future. In an economic sense, an investment is the purchase of goods that are not consumed today but are used in the future to create wealth. In finance, an investment is a monetary asset purchased with the idea that the asset will provide income in the future or appreciate and be sold at a higher price.",
"id": 3
}
},
"x": 759,
"y": 0,
"r": 8.277798660184793,
"layer": 0,
"sink": false
},
{
"id": 7,
"attributes": {
"x": 255,
"y": 250,
"color": "#2ca02c",
"radius": 5,
"shape": "circle",
"text": "Share Price"
},
"data": {
"categories": [
"Concept"
],
"properties": {
"name": "Share Price",
"definition": "The price of shares of a particular company at a particular time.",
"id": 2
}
},
"x": 674.6666666666667,
"y": 0,
"r": 10.763584846041306,
"layer": 0,
"sink": false
},
{
"id": 8,
"attributes": {
"x": 127.5,
"y": 250,
...