Politur: Gedaechnis-Graph-Visualisierung veredelt (Neon-Glow, radialer Hintergrundverlauf und reaktives Zoom-Scaling)
This commit is contained in:
@@ -9,16 +9,16 @@ import { type MemoryGraph } from "@/lib/api"
|
||||
// Fakten flüssig. Im App-Look gestylt; Hover hebt den Knoten + seine Nachbarn hervor, der Rest dimmt.
|
||||
|
||||
const CAT_COLOR: Record<string, string> = {
|
||||
identity: "#22d3ee", knowledge: "#6366f1", rules: "#a78bfa", events: "#fbbf24",
|
||||
identity: "#00f5ff", knowledge: "#3b82f6", rules: "#d946ef", events: "#fbbf24",
|
||||
}
|
||||
const CAT_LABEL: Record<string, string> = {
|
||||
identity: "Identität", knowledge: "Wissen", rules: "Regeln", events: "Ereignisse",
|
||||
}
|
||||
const AUTO = new Set(["auto", "agent", "hermes"])
|
||||
const DIM_NODE = "#1f2937"
|
||||
const DIM_EDGE = "#0f172a"
|
||||
const EDGE = "#243044"
|
||||
const EDGE_HI = "#4b5563"
|
||||
const DIM_NODE = "#1e293b"
|
||||
const DIM_EDGE = "rgba(15, 23, 42, 0.05)"
|
||||
const EDGE = "rgba(255, 255, 255, 0.07)"
|
||||
const EDGE_HI = "rgba(99, 102, 241, 0.85)"
|
||||
|
||||
export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id: string) => void }) {
|
||||
const [selected, setSelected] = useState<string | null>(null)
|
||||
@@ -43,39 +43,53 @@ export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id
|
||||
const a = (2 * Math.PI * i) / N
|
||||
graph.addNode(n.id, {
|
||||
x: Math.cos(a), y: Math.sin(a), // Startposition (Kreis) für ForceAtlas2
|
||||
size: 4 + Math.min(degree[n.id] || 0, 12) * 1.4,
|
||||
size: 5 + Math.min(degree[n.id] || 0, 12) * 1.5,
|
||||
color: CAT_COLOR[n.category] || "#64748b",
|
||||
label: n.content.length > 48 ? n.content.slice(0, 47) + "…" : n.content,
|
||||
})
|
||||
})
|
||||
data.edges.forEach((e) => {
|
||||
if (graph.hasNode(e.source) && graph.hasNode(e.target) && !graph.hasEdge(e.source, e.target))
|
||||
graph.addEdge(e.source, e.target, { size: 0.6 + (e.weight || 0), color: EDGE })
|
||||
graph.addEdge(e.source, e.target, { size: 0.8 + (e.weight || 0) * 0.5, color: EDGE })
|
||||
})
|
||||
forceAtlas2.assign(graph, { iterations: 220, settings: forceAtlas2.inferSettings(graph) })
|
||||
graphRef.current = graph
|
||||
|
||||
const renderer = new Sigma(graph, containerRef.current, {
|
||||
renderLabels: true,
|
||||
labelColor: { color: "#cbd5e1" },
|
||||
labelColor: { color: "#e2e8f0" },
|
||||
labelSize: 11,
|
||||
labelWeight: "500",
|
||||
labelDensity: 0.6,
|
||||
labelWeight: "600",
|
||||
labelDensity: 0.5,
|
||||
labelRenderedSizeThreshold: N > 120 ? 12 : 0, // bei vielen Knoten nur große labeln (entklumpen)
|
||||
defaultEdgeColor: EDGE,
|
||||
minCameraRatio: 0.1,
|
||||
maxCameraRatio: 4,
|
||||
nodeReducer: (id, attrs) => {
|
||||
const a = active.current
|
||||
if (!a) return attrs
|
||||
if (id === a || graph.areNeighbors(a, id)) return attrs
|
||||
const isSel = id === selectedRef.current
|
||||
|
||||
if (!a) {
|
||||
if (isSel) return { ...attrs, size: attrs.size * 1.35, highlighted: true }
|
||||
return attrs
|
||||
}
|
||||
|
||||
if (id === a) {
|
||||
return { ...attrs, size: attrs.size * 1.45, highlighted: true }
|
||||
}
|
||||
|
||||
if (graph.areNeighbors(a, id)) {
|
||||
if (isSel) return { ...attrs, size: attrs.size * 1.35, highlighted: true }
|
||||
return attrs
|
||||
}
|
||||
|
||||
return { ...attrs, color: DIM_NODE, label: "" }
|
||||
},
|
||||
edgeReducer: (edge, attrs) => {
|
||||
const a = active.current
|
||||
if (!a) return attrs
|
||||
const ext = graph.extremities(edge)
|
||||
if (ext[0] === a || ext[1] === a) return { ...attrs, color: EDGE_HI, size: (attrs.size || 1) * 1.6 }
|
||||
if (ext[0] === a || ext[1] === a) return { ...attrs, color: EDGE_HI, size: (attrs.size || 1) * 2.2 }
|
||||
return { ...attrs, color: DIM_EDGE }
|
||||
},
|
||||
})
|
||||
@@ -147,7 +161,8 @@ export function GraphView({ data, onDelete }: { data: MemoryGraph; onDelete: (id
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_300px] gap-3">
|
||||
<div className="relative h-[calc(100vh-13rem)] min-h-[560px] rounded-2xl border border-border/60 bg-[#070a0f] overflow-hidden">
|
||||
<div className="relative h-[calc(100vh-13rem)] min-h-[560px] rounded-2xl border border-border/60 overflow-hidden"
|
||||
style={{ background: "radial-gradient(circle at center, rgba(59, 130, 246, 0.06) 0%, #030712 100%)" }}>
|
||||
<div ref={containerRef} className="absolute inset-0" />
|
||||
<button onClick={relayout} title="Knoten neu anordnen"
|
||||
className="absolute right-3 top-3 z-10 flex items-center gap-1.5 rounded-lg border border-border/60 bg-background/50 px-2.5 py-1.5 text-[11px] text-muted-foreground hover:text-foreground backdrop-blur-sm transition-colors">
|
||||
|
||||
Reference in New Issue
Block a user