g6/packages/site/examples/net/layoutMechanism/demo/customBigraph.js
2023-08-29 15:19:51 +08:00

322 lines
6.6 KiB
JavaScript

import G6, { extend } from '@antv/g6';
const data = {
nodes: [
{
id: '0',
data: {
label: 'A',
cluster: 'part1',
},
},
{
id: '1',
data: {
label: 'B',
cluster: 'part1',
},
},
{
id: '2',
data: {
label: 'C',
cluster: 'part1',
},
},
{
id: '3',
data: {
label: 'D',
cluster: 'part1',
},
},
{
id: '4',
data: {
label: 'E',
cluster: 'part1',
},
},
{
id: '5',
data: {
label: 'F',
cluster: 'part1',
},
},
{
id: '6',
data: {
label: 'a',
cluster: 'part2',
},
},
{
id: '7',
data: {
label: 'b',
cluster: 'part2',
},
},
{
id: '8',
data: {
label: 'c',
cluster: 'part2',
},
},
{
id: '9',
data: {
label: 'd',
cluster: 'part2',
},
},
],
edges: [
{
id: 'edge-270',
source: '0',
target: '6',
},
{
id: 'edge-483',
source: '0',
target: '7',
},
{
id: 'edge-942',
source: '0',
target: '9',
},
{
id: 'edge-569',
source: '1',
target: '6',
},
{
id: 'edge-152',
source: '1',
target: '9',
},
{
id: 'edge-540',
source: '1',
target: '7',
},
{
id: 'edge-754',
source: '2',
target: '8',
},
{
id: 'edge-78',
source: '2',
target: '9',
},
{
id: 'edge-824',
source: '2',
target: '6',
},
{
id: 'edge-308',
source: '3',
target: '8',
},
{
id: 'edge-254',
source: '4',
target: '6',
},
{
id: 'edge-283',
source: '4',
target: '7',
},
{
id: 'edge-360',
source: '5',
target: '9',
},
],
};
class BiLayout {
// implements Layout<{}>
id = 'bi-layout';
constructor(options = {}) {
this.options = options;
}
/**
* Return the positions of nodes and edges(if needed).
*/
async execute(graph, options = {}) {
return this.genericLineLayout(false, graph, options);
}
/**
* To directly assign the positions to the nodes.
*/
async assign(graph, options = {}) {
this.genericLineLayout(true, graph, options);
}
async genericLineLayout(assign, graph, options = {}) {
const {
center = [0, 0],
biSep = 100,
nodeSep = 20,
nodeSize = 32,
direction = 'horizontal',
} = { ...this.options, ...options };
let part1Pos = 0;
let part2Pos = 0;
if (direction === 'horizontal') {
part1Pos = center[0] - biSep / 2;
part2Pos = center[0] + biSep / 2;
}
const nodes = graph.getAllNodes();
const edges = graph.getAllEdges();
const part1Nodes = [];
const part2Nodes = [];
const part1NodeMap = new Map();
const part2NodeMap = new Map();
// separate the nodes and init the positions
nodes.forEach(function (node, i) {
if (node.data.cluster === 'part1') {
part1Nodes.push(node);
part1NodeMap.set(node.id, i);
} else {
part2Nodes.push(node);
part2NodeMap.set(node.id, i);
}
});
// order the part1 node
const indexMap = {};
part1Nodes.forEach(function (p1n) {
let index = 0;
let adjCount = 0;
edges.forEach(function (edge) {
const sourceId = edge.source;
const targetId = edge.target;
if (sourceId === p1n.id) {
index += part2NodeMap.get(targetId);
adjCount += 1;
} else if (targetId === p1n.id) {
index += part2NodeMap.get(sourceId);
adjCount += 1;
}
});
index /= adjCount;
indexMap[p1n.id] = index;
});
part1Nodes.sort(function (a, b) {
return indexMap[a.id] - indexMap[b.id];
});
part2Nodes.forEach(function (p2n) {
let index = 0;
let adjCount = 0;
edges.forEach(function (edge) {
const sourceId = edge.source;
const targetId = edge.target;
if (sourceId === p2n.id) {
index += part1NodeMap.get(targetId);
adjCount += 1;
} else if (targetId === p2n.id) {
index += part1NodeMap.get(sourceId);
adjCount += 1;
}
});
index /= adjCount;
indexMap[p2n.id] = index;
});
part2Nodes.sort(function (a, b) {
return indexMap[a.id] - indexMap[b.id];
});
// 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 (direction === 'vertical') {
begin = center[0] - height / 2;
}
part1Nodes.forEach(function (p1n, i) {
if (direction === 'horizontal') {
p1n.data.x = part1Pos;
p1n.data.y = begin + i * (nodeSep + nodeSize);
} else {
p1n.data.x = begin + i * (nodeSep + nodeSize);
p1n.data.y = part1Pos;
}
});
part2Nodes.forEach(function (p2n, i) {
if (direction === 'horizontal') {
p2n.data.x = part2Pos;
p2n.data.y = begin + i * (nodeSep + nodeSize);
} else {
p2n.data.x = begin + i * (nodeSep + nodeSize);
p2n.data.y = part2Pos;
}
});
const result = {
nodes: part1Nodes.concat(part2Nodes).map((node) => ({ id: node.id, data: { x: node.data.x, y: node.data.y } })),
edges,
};
if (assign) {
layoutNodes.forEach((node) => {
graph.mergeNodeData(node.id, {
x: node.data.x,
y: node.data.y,
});
});
}
return result;
}
}
const CustomGraph = extend(G6.Graph, {
layouts: {
'bi-layout': BiLayout,
},
});
const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new CustomGraph({
container: 'container',
width,
height,
layout: {
type: 'bi-layout',
biSep: 300,
nodeSep: 20,
nodeSize: 32,
},
theme: {
type: 'spec',
specification: {
node: {
dataTypeField: 'cluster',
},
},
},
modes: {
default: ['drag-canvas', 'drag-node', 'zoom-canvas', 'click-select'],
},
data,
});
if (typeof window !== 'undefined')
window.onresize = () => {
if (!graph || graph.destroyed) return;
if (!container || !container.scrollWidth || !container.scrollHeight) return;
graph.setSize([container.scrollWidth, container.scrollHeight]);
};