Politur: d3Force-Kollision und Quadranten-Clustering korrigiert (Zentrumskraft entfernt, starker charge-Faktor und farbkodierte Kanten)

This commit is contained in:
Hitonabi
2026-07-09 12:23:23 +02:00
parent a261462857
commit 895eb9cac7
4 changed files with 30 additions and 31 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="manifest" href="/manifest.webmanifest" /> <link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title> <title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-DNXEzn-Z.js"></script> <script type="module" crossorigin src="/assets/index-Ch3qlJmN.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-1USExdfg.css"> <link rel="stylesheet" crossorigin href="/assets/index-1USExdfg.css">
</head> </head>
<body> <body>
+26 -27
View File
@@ -11,7 +11,7 @@ const CAT_LABEL: Record<string, string> = {
identity: "Identität", knowledge: "Wissen", rules: "Regeln", events: "Ereignisse", identity: "Identität", knowledge: "Wissen", rules: "Regeln", events: "Ereignisse",
} }
const AUTO = new Set(["auto", "agent", "hermes"]) const AUTO = new Set(["auto", "agent", "hermes"])
const EDGE_HI = "rgba(99, 102, 241, 0.85)" const EDGE_HI = "rgba(99, 102, 241, 0.9)"
const DIM_EDGE = "rgba(255, 255, 255, 0.02)" const DIM_EDGE = "rgba(255, 255, 255, 0.02)"
// Hilfsfunktion zur Konvertierung von Hex in RGBA für farbkodierte Verbindungen // Hilfsfunktion zur Konvertierung von Hex in RGBA für farbkodierte Verbindungen
@@ -68,22 +68,22 @@ export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id
return d return d
}, [data]) }, [data])
// Quadranten-Fokuskoordinaten für sauberes Clustering // Quadranten-Fokuskoordinaten für sauberes Clustering (Fokuszentren weiter auseinander gezogen)
const getClusterX = (category: string) => { const getClusterX = (category: string) => {
return { return {
identity: -160, identity: -220,
knowledge: 160, knowledge: 220,
rules: -160, rules: -220,
events: 160, events: 220,
}[category] || 0 }[category] || 0
} }
const getClusterY = (category: string) => { const getClusterY = (category: string) => {
return { return {
identity: -160, identity: -220,
knowledge: -160, knowledge: -220,
rules: 160, rules: 220,
events: 160, events: 220,
}[category] || 0 }[category] || 0
} }
@@ -92,26 +92,25 @@ export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id
const fg = fgRef.current const fg = fgRef.current
if (!fg) return if (!fg) return
// 1. Clustering-Kräfte (Knoten zu ihren jeweiligen Sektions-Foci ziehen) // 1. Standard-Zentrumskraft entfernen (erlaubt freies Clustering in Quadranten)
fg.d3Force("x", forceX().x((node: any) => getClusterX(node.category)).strength(0.14)) fg.d3Force("center", null)
fg.d3Force("y", forceY().y((node: any) => getClusterY(node.category)).strength(0.14))
// 2. Kollisionskraft (Verhindert, dass Knoten und Textlabels ineinandergeschoben werden) // 2. Clustering-Kräfte (Knoten zu ihren jeweiligen Sektions-Foci ziehen)
fg.d3Force("collide", forceCollide().radius((node: any) => { fg.d3Force("x", forceX().x((node: any) => getClusterX(node.category)).strength(0.18))
const nodeDegree = degree[node.id] || 0 fg.d3Force("y", forceY().y((node: any) => getClusterY(node.category)).strength(0.18))
// Radius = Knotengröße + großzügiger Textpuffer
return 28 + Math.min(nodeDegree, 12) * 1.5
}).iterations(2))
// 3. Abstoßung (Charge) moderat, da collide und foci die Hauptarbeit leisten // 3. Starke Abstoßung (Charge) für ein weit gefächertes, luftiges Netz
const charge = fg.d3Force("charge") const charge = fg.d3Force("charge")
if (charge) charge.strength(-60) if (charge) charge.strength(-240)
// 4. Federn (Links) // 4. Kollisionskraft (Fester, sicherer Radius, verhindert Überlappung)
fg.d3Force("collide", forceCollide().radius(34).iterations(2))
// 5. Federkraft (Links)
const link = fg.d3Force("link") const link = fg.d3Force("link")
if (link) link.distance(50) if (link) link.distance(60)
// Simulation neu anschubsen bei neuen Daten // Simulation neu starten (Reheat)
fg.d3ReheatSimulation() fg.d3ReheatSimulation()
}, [graphData]) }, [graphData])
@@ -191,15 +190,15 @@ export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id
// Wenn ein anderer Knoten aktiv ist, blenden wir diese Kante fast komplett aus // Wenn ein anderer Knoten aktiv ist, blenden wir diese Kante fast komplett aus
if (activeNode) return DIM_EDGE if (activeNode) return DIM_EDGE
// Standard-Zustand: Kante leuchtet dezent in der Farbe der Kategorie des Quell-Knotens // Standard-Zustand: Kante leuchtet in der Farbe des Quell-Clusters (deutlich sichtbar mit alpha=0.25)
const sourceNode = graphData.nodes.find(n => n.id === sId) const sourceNode = graphData.nodes.find(n => n.id === sId)
const catColor = sourceNode ? CAT_COLOR[sourceNode.category] : "#64748b" const catColor = sourceNode ? CAT_COLOR[sourceNode.category] : "#64748b"
return hexToRgba(catColor, 0.16) return hexToRgba(catColor, 0.25)
}} }}
linkWidth={(link: any) => { linkWidth={(link: any) => {
const sId = typeof link.source === "object" ? link.source.id : link.source const sId = typeof link.source === "object" ? link.source.id : link.source
const tId = typeof link.target === "object" ? link.target.id : link.target const tId = typeof link.target === "object" ? link.target.id : link.target
return (activeNode === sId || activeNode === tId) ? 2.5 : 1.2 return (activeNode === sId || activeNode === tId) ? 2.5 : 1.4
}} }}
// Daten-Partikel fließen auf den aktiven Verbindungen // Daten-Partikel fließen auf den aktiven Verbindungen