Appearance
Multilevel Grouping new
This example shows how to use the nodeGrouping transformation to create three levels of grouping in a graph.
ts
import Ogma, { NodeList } from '@linkurious/ogma';
const ogma = new Ogma<NodeData>({
container: 'graph-container'
});
interface NodeData {
name: string;
lang: string;
size: number;
country: string;
level?: number;
}
ogma.styles.setTheme({
nodeAttributes: {
innerStroke: {
color: 'white',
width: 1,
minVisibleSize: 30
},
outerStroke: {
color: 'black',
width: 2,
scalingMethod: 'scaled',
minVisibleSize: 10
},
text: {
backgroundColor: null,
size: 14,
minVisibleSize: 0,
padding: 4
},
radius: 7
},
selectedNodeAttributes: {
outline: false,
outerStroke: {
color: '#222',
scalingMethod: 'fixed',
width: 6
},
innerStroke: {
color: 'white',
scalingMethod: 'fixed',
width: 6,
minVisibleSize: 0
},
text: {
backgroundColor: 'white'
}
},
hoveredNodeAttributes: {
outline: false,
outerStroke: {
color: '#222',
scalingMethod: 'fixed',
width: 4
},
innerStroke: {
color: 'white',
scalingMethod: 'fixed',
width: 4,
minVisibleSize: 0
},
text: {
color: '#fff',
backgroundColor: '#222'
}
},
edgeAttributes: {},
hoveredEdgeAttributes: {
color: '#222',
width: 3,
stroke: {
color: '#fff',
width: 2
},
text: { color: '#fff' }
},
selectedEdgeAttributes: {
color: '#222',
width: 4,
stroke: {
color: '#fff',
width: 2
}
}
});
// three bright pastel colors for the group nodes
const colors = ['#f9a03f', '#f9e03f'];
ogma.styles.addNodeRule({
color: node =>
!node.isVirtual()
? '#333'
: node.getData('level') === 1
? colors[0]
: colors[1],
text: {
content: node =>
node.isVirtual() ? node.getData('label') : node.getData('name'),
minVisibleSize: node => (node.isVirtual() ? 30 : 12),
size: 10, // node => (node.isVirtual() ? 12 : 12),
color: '#fff',
backgroundColor: node => '#333'
}
});
ogma.styles.createClass({
name: 'hovered-group',
edgeAttributes: {
color: '#fff',
width: 2
}
});
const layer = ogma.layers.addLayer(`<div class='loader'>
<svg version="1.1" id="L3" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<circle fill="none" stroke="#fff" stroke-width="4" cx="50" cy="50" r="44" style="opacity:1;"/>
<circle fill="#222" cx="8" cy="54" r="6" >
<animateTransform
attributeName="transform"
dur="2s"
type="rotate"
from="0 50 48"
to="360 50 52"
repeatCount="indefinite" />
</circle>
</svg>
</div>`);
const graph = await Ogma.parse.jsonFromUrl<NodeData>('files/github.json');
graph.nodes = graph.nodes
.filter(node => node.data && node.data.country)
.slice(1000, 1200)
.map(node => ({
...node,
attributes: undefined
}));
graph.edges = graph.edges.map(edge => ({
...edge,
attributes: undefined
}));
await ogma.setGraph(graph, { ignoreInvalid: true });
await ogma.layouts.force({ gpu: true, locate: true });
await ogma.transformations
.addNodeGrouping({
groupIdFunction: node =>
`${node.getData('lang')}_${node.getData('country')}`,
nodeGenerator: (nodes, groupId) => {
const [lang, country] = groupId.split('_');
return {
data: {
level: 1,
lang,
label: lang,
country
}
};
},
padding: 20,
showContents: true
})
.whenApplied();
await Promise.all(
ogma
.getNodes()
.filter(n => n.isVirtual())
.map(group =>
ogma.layouts.hierarchical({
nodes: group.getSubNodes() as NodeList,
duration: 0
})
)
);
await ogma.transformations
.addNodeGrouping({
selector: node => node.getData('level') === 1,
groupIdFunction: node => `${node.getData('country')}`,
nodeGenerator: (nodes, groupId) => {
return {
data: {
level: 2,
country: groupId,
label: groupId
}
};
},
padding: 20,
showContents: true
})
.whenApplied();
await Promise.all(
ogma
.getNodes()
.filter(n => n.getData('level') === 2)
.map(group =>
ogma.layouts.force({
nodes: group.getSubNodes() as NodeList,
charge: 40,
radiusRatio: 2,
gravity: 0.01,
edgeStrength: 0.25,
duration: 0
})
)
);
await ogma.layouts.force({
nodes: ogma.getNodes().filter(n => n.getData('level') === 2),
theta: 0.9,
edgeStrength: 0.25,
gravity: 0.01,
locate: true
});
layer.element.classList.add('fadeout');
setTimeout(() => layer.hide(), 1000);
html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<!---->
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="graph-container"></div>
<div id="info" class="info"></div>
<script type="module" src="index.ts"></script>
</body>
</html>
css
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: 0;
overflow: hidden;
}
.loader {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
background: #ddd;
opacity: 0.9;
}
.loader > svg{
width: 25%;
opacity: 1;
}
.fadeout{
animation: fadeout 1s;
}
@keyframes fadeout {
from { opacity: 1; }
to { opacity: 0; }
}