update
This commit is contained in:
@@ -160,18 +160,7 @@ export class GraphView {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
layout: {
|
layout: { name: "preset", fit: true, padding: 30 },
|
||||||
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,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// @ts-ignore — added by cytoscape-node-html-label
|
// @ts-ignore — added by cytoscape-node-html-label
|
||||||
@@ -191,7 +180,6 @@ export class GraphView {
|
|||||||
|
|
||||||
private buildElements(data: GraphData, collections: string[]): cytoscape.ElementDefinition[] {
|
private buildElements(data: GraphData, collections: string[]): cytoscape.ElementDefinition[] {
|
||||||
const els: cytoscape.ElementDefinition[] = [];
|
const els: cytoscape.ElementDefinition[] = [];
|
||||||
els.push({ data: { id: ROOT_ID, label: this.project, depth: 0 } });
|
|
||||||
|
|
||||||
const childrenMap = new Map<string | null, string[]>();
|
const childrenMap = new Map<string | null, string[]>();
|
||||||
for (const e of data.edges) {
|
for (const e of data.edges) {
|
||||||
@@ -201,6 +189,13 @@ export class GraphView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const known = new Set(collections);
|
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 visited = new Set<string>();
|
||||||
const walk = (parentName: string | null, parentId: string, depth: number) => {
|
const walk = (parentName: string | null, parentId: string, depth: number) => {
|
||||||
const children = (childrenMap.get(parentName) ?? []).filter((c) => known.has(c));
|
const children = (childrenMap.get(parentName) ?? []).filter((c) => known.has(c));
|
||||||
@@ -213,6 +208,7 @@ export class GraphView {
|
|||||||
const { w, h } = this.nodeSize(features.length);
|
const { w, h } = this.nodeSize(features.length);
|
||||||
els.push({
|
els.push({
|
||||||
data: { id, name: child, depth, features, w, h },
|
data: { id, name: child, depth, features, w, h },
|
||||||
|
position: positions.get(id) ?? { x: 0, y: 0 },
|
||||||
});
|
});
|
||||||
els.push({ data: { source: parentId, target: id } });
|
els.push({ data: { source: parentId, target: id } });
|
||||||
walk(child, id, depth + 1);
|
walk(child, id, depth + 1);
|
||||||
@@ -222,6 +218,52 @@ export class GraphView {
|
|||||||
return els;
|
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 } {
|
private nodeSize(featureCount: number): { w: number; h: number } {
|
||||||
const w = 180;
|
const w = 180;
|
||||||
const rows = Math.max(1, Math.ceil(featureCount / 2));
|
const rows = Math.max(1, Math.ceil(featureCount / 2));
|
||||||
|
|||||||
Reference in New Issue
Block a user