update
This commit is contained in:
@@ -160,18 +160,7 @@ export class GraphView {
|
||||
},
|
||||
},
|
||||
],
|
||||
layout: {
|
||||
name: "concentric",
|
||||
concentric: (node) => -((node.data("depth") as number) ?? 0),
|
||||
levelWidth: () => 1,
|
||||
minNodeSpacing: 40,
|
||||
// @ts-ignore — spacingFactor exists in concentric layout
|
||||
spacingFactor: 0.9,
|
||||
fit: true,
|
||||
padding: 30,
|
||||
startAngle: -Math.PI / 2,
|
||||
clockwise: true,
|
||||
},
|
||||
layout: { name: "preset", fit: true, padding: 30 },
|
||||
});
|
||||
|
||||
// @ts-ignore — added by cytoscape-node-html-label
|
||||
@@ -191,7 +180,6 @@ export class GraphView {
|
||||
|
||||
private buildElements(data: GraphData, collections: string[]): cytoscape.ElementDefinition[] {
|
||||
const els: cytoscape.ElementDefinition[] = [];
|
||||
els.push({ data: { id: ROOT_ID, label: this.project, depth: 0 } });
|
||||
|
||||
const childrenMap = new Map<string | null, string[]>();
|
||||
for (const e of data.edges) {
|
||||
@@ -201,6 +189,13 @@ export class GraphView {
|
||||
}
|
||||
|
||||
const known = new Set(collections);
|
||||
const positions = this.computePositions(childrenMap, known);
|
||||
|
||||
els.push({
|
||||
data: { id: ROOT_ID, label: this.project, depth: 0 },
|
||||
position: positions.get(ROOT_ID) ?? { x: 0, y: 0 },
|
||||
});
|
||||
|
||||
const visited = new Set<string>();
|
||||
const walk = (parentName: string | null, parentId: string, depth: number) => {
|
||||
const children = (childrenMap.get(parentName) ?? []).filter((c) => known.has(c));
|
||||
@@ -213,6 +208,7 @@ export class GraphView {
|
||||
const { w, h } = this.nodeSize(features.length);
|
||||
els.push({
|
||||
data: { id, name: child, depth, features, w, h },
|
||||
position: positions.get(id) ?? { x: 0, y: 0 },
|
||||
});
|
||||
els.push({ data: { source: parentId, target: id } });
|
||||
walk(child, id, depth + 1);
|
||||
@@ -222,6 +218,52 @@ export class GraphView {
|
||||
return els;
|
||||
}
|
||||
|
||||
private computePositions(
|
||||
childrenMap: Map<string | null, string[]>,
|
||||
known: Set<string>,
|
||||
): Map<string, { x: number; y: number }> {
|
||||
const R1 = 220;
|
||||
const STEP = 200;
|
||||
const positions = new Map<string, { x: number; y: number }>();
|
||||
positions.set(ROOT_ID, { x: 0, y: 0 });
|
||||
|
||||
const direct = (childrenMap.get(null) ?? []).filter((c) => known.has(c));
|
||||
const N = Math.max(direct.length, 1);
|
||||
const sectorPerDirect = (2 * Math.PI) / N;
|
||||
|
||||
const layoutSubtree = (
|
||||
parentName: string,
|
||||
parentAngle: number,
|
||||
allowedSector: number,
|
||||
parentRadius: number,
|
||||
) => {
|
||||
const children = (childrenMap.get(parentName) ?? []).filter((c) => known.has(c));
|
||||
const k = children.length;
|
||||
if (k === 0) return;
|
||||
const newRadius = parentRadius + STEP;
|
||||
const perChild = allowedSector / k;
|
||||
for (let i = 0; i < k; i++) {
|
||||
const angle = parentAngle - allowedSector / 2 + (i + 0.5) * perChild;
|
||||
positions.set(`n_${children[i]}`, {
|
||||
x: Math.cos(angle) * newRadius,
|
||||
y: Math.sin(angle) * newRadius,
|
||||
});
|
||||
layoutSubtree(children[i], angle, perChild, newRadius);
|
||||
}
|
||||
};
|
||||
|
||||
direct.forEach((child, i) => {
|
||||
const angle = i * sectorPerDirect - Math.PI / 2;
|
||||
positions.set(`n_${child}`, {
|
||||
x: Math.cos(angle) * R1,
|
||||
y: Math.sin(angle) * R1,
|
||||
});
|
||||
layoutSubtree(child, angle, sectorPerDirect, R1);
|
||||
});
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
private nodeSize(featureCount: number): { w: number; h: number } {
|
||||
const w = 180;
|
||||
const rows = Math.max(1, Math.ceil(featureCount / 2));
|
||||
|
||||
Reference in New Issue
Block a user