g6/demos/layout-custom-bigraph.html
2019-10-10 20:01:23 +08:00

261 lines
6.5 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Bigraph Layout</title>
</head>
<body>
<div id="description">自定义布局二分图,根据二分图中每个部分节点与另一部分的连接关系,对节点进行排序以减少边的交错</div>
<div id="mountNode"></div>
<script src="../build/g6.js"></script>
<script>
const data = {
"nodes": [{
"id": "0",
"label": "A",
"cluster": "part1"
},
{
"id": "1",
"label": "B",
"cluster": "part1"
},
{
"id": "2",
"label": "C",
"cluster": "part1"
},
{
"id": "3",
"label": "D",
"cluster": "part1"
},
{
"id": "4",
"label": "E",
"cluster": "part1"
},
{
"id": "5",
"label": "F",
"cluster": "part1"
},
{
"id": "6",
"label": "a",
"cluster": "part2"
},
{
"id": "7",
"label": "b",
"cluster": "part2"
},
{
"id": "8",
"label": "c",
"cluster": "part2"
},
{
"id": "9",
"label": "d",
"cluster": "part2"
}],
"edges": [{
"source": "0",
"target": "6"
},
{
"source": "0",
"target": "7"
},
{
"source": "0",
"target": "9"
},
{
"source": "1",
"target": "6"
},
{
"source": "1",
"target": "9"
},
{
"source": "1",
"target": "7"
},
{
"source": "2",
"target": "8"
},
{
"source": "2",
"target": "9"
},
{
"source": "2",
"target": "6"
},
{
"source": "3",
"target": "8"
},
{
"source": "4",
"target": "6"
},
{
"source": "4",
"target": "7"
},
{
"source": "5",
"target": "9"
}]
};
G6.registerLayout('bigraph-layout', {
getDefaultCfg() {
return {
center: [ 0, 0 ],
biSep: 100,
nodeSep: 20,
direction: 'horizontal',
nodeSize: 20
};
},
execute() {
const self = this;
const center = self.center;
const biSep = self.biSep;
const nodeSep = self.nodeSep;
const nodeSize = self.nodeSize;
let part1Pos = 0, part2Pos = 0;
if (self.direction === 'horizontal') {
part1Pos = center[0] - biSep / 2;
part2Pos = center[0] + biSep / 2;
}
const nodes = self.nodes;
const edges = self.edges;
const part1Nodes = [];
const part2Nodes = [];
const part1NodeMap = new Map();
const part2NodeMap = new Map();
// separate the nodes and init the positions
nodes.forEach((node, i) => {
if (node.cluster === 'part1') {
part1Nodes.push(node);
part1NodeMap.set(node.id, i);
} else {
part2Nodes.push(node);
part2NodeMap.set(node.id, i);
}
});
// order the part1 node
part1Nodes.forEach((p1n => {
let index = 0;
let adjCount = 0;
edges.forEach(edge => {
const sourceId = edge.source;
const targetId = edge.target;
if (sourceId === p1n.id) {
index += part2NodeMap.get(targetId);
adjCount ++;
} else if (targetId === p1n.id) {
index += part2NodeMap.get(sourceId);
adjCount ++;
}
});
index /= adjCount;
p1n.index = index;
}));
part1Nodes.sort(function(a, b){
return a.index - b.index
})
part2Nodes.forEach((p2n => {
let index = 0;
let adjCount = 0;
edges.forEach(edge => {
const sourceId = edge.source;
const targetId = edge.target;
if (sourceId === p2n.id) {
index += part1NodeMap.get(targetId);
adjCount ++;
} else if (targetId === p2n.id) {
index += part1NodeMap.get(sourceId);
adjCount ++;
}
});
index /= adjCount;
p2n.index = index;
}));
part2Nodes.sort(function(a, b){
return a.index - b.index
})
// place the nodes
const hLength = part1Nodes.length > part2Nodes.length ? part1Nodes.length : part2Nodes.length;
const height = hLength * (nodeSep + nodeSize);
let begin = center[1] - height / 2;
if (self.direction === 'vertical') {
begin = center[0] - height / 2;
}
part1Nodes.forEach((p1n, i) => {
if (self.direction === 'horizontal') {
p1n.x = part1Pos;
p1n.y = begin + i * (nodeSep + nodeSize);
} else {
p1n.x = begin + i * (nodeSep + nodeSize);
p1n.y = part1Pos;
}
});
part2Nodes.forEach((p2n, i) => {
if (self.direction === 'horizontal') {
p2n.x = part2Pos;
p2n.y = begin + i * (nodeSep + nodeSize);
} else {
p2n.x = begin + i * (nodeSep + nodeSize);
p2n.y = part2Pos;
}
});
}
}, 'mds');
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
layout: {
type: 'bigraph-layout',
biSep: 300,
nodeSep: 50,
nodeSize: 20
},
animate: true,
defaultNode: {
size: [ 20, 20 ],
color: 'steelblue',
style: {
lineWidth: 2,
fill: '#fff'
},
},
defaultEdge: {
size: 1,
color: '#e2e2e2'
},
nodeStateStyles: {
selected: {
fill: 'steelblue'
}
}
});
graph.data(data);
graph.render();
</script>
</body>
</html>