feat: add self to graph
This commit is contained in:
@@ -105,10 +105,13 @@ function buildGraphArrays(
|
|||||||
theme: ReturnType<typeof getThemeStatusColors>,
|
theme: ReturnType<typeof getThemeStatusColors>,
|
||||||
): BuiltGraph {
|
): BuiltGraph {
|
||||||
const interfaces = rawNodes.filter(e => e.type === "interface").sort((a, b) => a.name.localeCompare(b.name));
|
const interfaces = rawNodes.filter(e => e.type === "interface").sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
const selfNode = rawNodes.find(e => e.is_self && e.type !== "interface");
|
||||||
const peers = rawNodes.filter(e => !e.is_self && e.type !== "interface");
|
const peers = rawNodes.filter(e => !e.is_self && e.type !== "interface");
|
||||||
|
|
||||||
// Only peers are points — interfaces are clusters, not nodes
|
// Peers + self node are points — interfaces are clusters, not nodes
|
||||||
const entries = peers;
|
// Self node goes first so it's easy to find by index
|
||||||
|
const entries = selfNode ? [selfNode, ...peers] : peers;
|
||||||
|
const selfIndex = selfNode ? 0 : -1;
|
||||||
const n = entries.length;
|
const n = entries.length;
|
||||||
const nClusters = interfaces.length;
|
const nClusters = interfaces.length;
|
||||||
const hashToIndex = new Map<string, number>();
|
const hashToIndex = new Map<string, number>();
|
||||||
@@ -119,11 +122,13 @@ function buildGraphArrays(
|
|||||||
const clusterStrength = new Float32Array(n);
|
const clusterStrength = new Float32Array(n);
|
||||||
|
|
||||||
// Cluster map: interface name → cluster index
|
// Cluster map: interface name → cluster index
|
||||||
|
// Self node gets its own cluster at the end
|
||||||
const clusterMap = new Map<string, number>();
|
const clusterMap = new Map<string, number>();
|
||||||
interfaces.forEach((iface, i) => clusterMap.set(iface.name, i));
|
interfaces.forEach((iface, i) => clusterMap.set(iface.name, i));
|
||||||
|
const selfClusterIndex = interfaces.length;
|
||||||
|
|
||||||
// Cluster names for labels
|
// Cluster names for labels
|
||||||
const clusterNames = interfaces.map(i => i.name);
|
const clusterNames = [...interfaces.map(i => i.name), ...(selfNode ? [selfNode.name] : [])];
|
||||||
|
|
||||||
// No explicit cluster positions — let cosmos use centermass
|
// No explicit cluster positions — let cosmos use centermass
|
||||||
const clusterPositions: (number | undefined)[] = [];
|
const clusterPositions: (number | undefined)[] = [];
|
||||||
@@ -141,8 +146,10 @@ function buildGraphArrays(
|
|||||||
positions[i * 2 + 1] = CENTER + (Math.random() - 0.5) * SPACE_SIZE * 0.5;
|
positions[i * 2 + 1] = CENTER + (Math.random() - 0.5) * SPACE_SIZE * 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colors — by status
|
// Colors — self node uses bright white, others by status
|
||||||
const rgba = statusRGBA(entry, theme);
|
const rgba = i === selfIndex
|
||||||
|
? [1, 1, 1, 1] as [number, number, number, number]
|
||||||
|
: statusRGBA(entry, theme);
|
||||||
colors[i * 4 + 0] = rgba[0];
|
colors[i * 4 + 0] = rgba[0];
|
||||||
colors[i * 4 + 1] = rgba[1];
|
colors[i * 4 + 1] = rgba[1];
|
||||||
colors[i * 4 + 2] = rgba[2];
|
colors[i * 4 + 2] = rgba[2];
|
||||||
@@ -150,11 +157,15 @@ function buildGraphArrays(
|
|||||||
|
|
||||||
sizes[i] = 3;
|
sizes[i] = 3;
|
||||||
|
|
||||||
// Cluster assignment — map to parent interface
|
// Cluster assignment — self node gets its own cluster, peers map to parent interface
|
||||||
const pi = peers.indexOf(entry);
|
if (i === selfIndex) {
|
||||||
const parentHash = findParentIface(entry, interfaces, pi);
|
clusterIndices.push(selfClusterIndex);
|
||||||
const parentName = parentHash ? interfaces.find(f => f.hash === parentHash)?.name : undefined;
|
} else {
|
||||||
clusterIndices.push(parentName !== undefined ? clusterMap.get(parentName) : undefined);
|
const pi = peers.indexOf(entry);
|
||||||
|
const parentHash = findParentIface(entry, interfaces, pi);
|
||||||
|
const parentName = parentHash ? interfaces.find(f => f.hash === parentHash)?.name : undefined;
|
||||||
|
clusterIndices.push(parentName !== undefined ? clusterMap.get(parentName) : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
// Cluster strength
|
// Cluster strength
|
||||||
clusterStrength[i] = nClusters > 1 ? (nClusters - (i % nClusters)) / nClusters : 1;
|
clusterStrength[i] = nClusters > 1 ? (nClusters - (i % nClusters)) / nClusters : 1;
|
||||||
@@ -263,14 +274,16 @@ export default function BrowseView() {
|
|||||||
div.style.pointerEvents = "none";
|
div.style.pointerEvents = "none";
|
||||||
div.style.whiteSpace = "nowrap";
|
div.style.whiteSpace = "nowrap";
|
||||||
div.style.transform = "translate(-50%, -100%)";
|
div.style.transform = "translate(-50%, -100%)";
|
||||||
div.style.padding = "2px 8px";
|
div.style.padding = "0";
|
||||||
div.style.borderRadius = "4px";
|
div.style.background = "none";
|
||||||
div.style.background = "var(--popover)";
|
div.style.border = "none";
|
||||||
div.style.border = "1px solid var(--border)";
|
|
||||||
div.style.color = "var(--foreground)";
|
div.style.color = "var(--foreground)";
|
||||||
div.style.fontFamily = "JetBrains Mono, monospace";
|
div.style.fontFamily = "JetBrains Mono, monospace";
|
||||||
div.style.fontSize = "11px";
|
div.style.fontSize = "14px";
|
||||||
div.style.boxShadow = "0 2px 8px rgba(0,0,0,0.3)";
|
div.style.fontWeight = "700";
|
||||||
|
div.style.letterSpacing = "0.05em";
|
||||||
|
div.style.textTransform = "uppercase";
|
||||||
|
div.style.opacity = "0.85";
|
||||||
div.textContent = names[i] ?? "";
|
div.textContent = names[i] ?? "";
|
||||||
container.appendChild(div);
|
container.appendChild(div);
|
||||||
labelDivsRef.current.push(div);
|
labelDivsRef.current.push(div);
|
||||||
|
|||||||
Reference in New Issue
Block a user