feat(rnetwork): concentric spheres layout with Fibonacci distribution
Replace flat ring layout with 3D sphere distribution using Fibonacci spiral for even node placement. Wireframe sphere guides replace flat ring guides — visible from every camera angle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
246b51b2e0
commit
03de21ddd5
|
|
@ -1075,9 +1075,9 @@ class FolkGraphViewer extends HTMLElement {
|
|||
n.fx = 0; n.fy = 0; n.fz = 0;
|
||||
}
|
||||
|
||||
this.placeRing(adminNodes, 30);
|
||||
this.placeRing(memberNodes, 80);
|
||||
this.placeRing(viewerNodes, 160);
|
||||
this.placeSphere(adminNodes, 30);
|
||||
this.placeSphere(memberNodes, 80);
|
||||
this.placeSphere(viewerNodes, 160);
|
||||
|
||||
this.graph.graphData(data);
|
||||
this.graph.d3ReheatSimulation();
|
||||
|
|
@ -1087,14 +1087,18 @@ class FolkGraphViewer extends HTMLElement {
|
|||
this.addRingGuides();
|
||||
}
|
||||
|
||||
private placeRing(nodes: GraphNode[], radius: number) {
|
||||
private placeSphere(nodes: GraphNode[], radius: number) {
|
||||
const count = nodes.length;
|
||||
if (count === 0) return;
|
||||
// Fibonacci sphere — even distribution on a sphere surface
|
||||
const goldenAngle = Math.PI * (3 - Math.sqrt(5));
|
||||
for (let i = 0; i < count; i++) {
|
||||
const angle = (2 * Math.PI * i) / count;
|
||||
nodes[i].fx = Math.cos(angle) * radius;
|
||||
nodes[i].fy = 0;
|
||||
nodes[i].fz = Math.sin(angle) * radius;
|
||||
const y = 1 - (2 * i) / (count - 1 || 1); // -1 to 1
|
||||
const r = Math.sqrt(1 - y * y);
|
||||
const theta = goldenAngle * i;
|
||||
nodes[i].fx = Math.cos(theta) * r * radius;
|
||||
nodes[i].fy = y * radius;
|
||||
nodes[i].fz = Math.sin(theta) * r * radius;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1116,23 +1120,22 @@ class FolkGraphViewer extends HTMLElement {
|
|||
const scene = this.graph.scene();
|
||||
if (!scene) return;
|
||||
|
||||
const ringRadii = [
|
||||
const sphereRadii = [
|
||||
{ r: 30, color: 0xa78bfa, label: "Admin" },
|
||||
{ r: 80, color: 0x10b981, label: "Member" },
|
||||
{ r: 160, color: 0x3b82f6, label: "Viewer" },
|
||||
];
|
||||
|
||||
for (const { r, color } of ringRadii) {
|
||||
const geometry = new THREE.RingGeometry(r - 0.5, r + 0.5, 128);
|
||||
for (const { r, color } of sphereRadii) {
|
||||
// Wireframe sphere guide
|
||||
const geometry = new THREE.SphereGeometry(r, 24, 16);
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
color,
|
||||
transparent: true,
|
||||
opacity: 0.15,
|
||||
side: THREE.DoubleSide,
|
||||
opacity: 0.06,
|
||||
wireframe: true,
|
||||
});
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.rotation.x = -Math.PI / 2; // flat on XZ plane
|
||||
mesh.position.y = 0;
|
||||
scene.add(mesh);
|
||||
this.ringGuides.push(mesh);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue