mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-15 20:05:13 +02:00
Dynamic (#77)
This commit is contained in:
parent
55247b7fcd
commit
991c84a1eb
1464 changed files with 225448 additions and 1985 deletions
123
frontend/src/graph/components/SurfaceGraphCanvas.tsx
Normal file
123
frontend/src/graph/components/SurfaceGraphCanvas.tsx
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
import type { SurfaceMap } from '@/api/types';
|
||||
import { adaptSurfaceMap } from '../adapters/surface';
|
||||
import { useElkLayout } from '../hooks/useElkLayout';
|
||||
import {
|
||||
collectSearchMatches,
|
||||
extractNeighborhoodSubgraph,
|
||||
} from '../reduction/neighborhood';
|
||||
import { SigmaGraph } from '../rendering/sigma/SigmaGraph';
|
||||
|
||||
interface SurfaceGraphCanvasProps {
|
||||
data: SurfaceMap;
|
||||
selectedNodeId: number | null;
|
||||
onSelectNode: (id: number) => void;
|
||||
}
|
||||
|
||||
export function SurfaceGraphCanvas({
|
||||
data,
|
||||
selectedNodeId,
|
||||
onSelectNode,
|
||||
}: SurfaceGraphCanvasProps) {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [neighborhoodOnly, setNeighborhoodOnly] = useState(false);
|
||||
const [radius, setRadius] = useState(2);
|
||||
|
||||
const fullGraph = useMemo(() => adaptSurfaceMap(data), [data]);
|
||||
const selectedNodeKey =
|
||||
selectedNodeId == null ? null : String(selectedNodeId);
|
||||
|
||||
const matches = useMemo(
|
||||
() => collectSearchMatches(fullGraph, searchQuery, 60),
|
||||
[fullGraph, searchQuery],
|
||||
);
|
||||
const matchKeys = useMemo(
|
||||
() => new Set(matches.map((node) => node.key)),
|
||||
[matches],
|
||||
);
|
||||
|
||||
const visibleGraph = useMemo(() => {
|
||||
if (!neighborhoodOnly || !selectedNodeKey) return fullGraph;
|
||||
return extractNeighborhoodSubgraph(fullGraph, selectedNodeKey, radius);
|
||||
}, [fullGraph, neighborhoodOnly, radius, selectedNodeKey]);
|
||||
|
||||
const { graph, isLoading, error } = useElkLayout(visibleGraph);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="error-state">Failed to compute the surface layout.</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!graph) {
|
||||
return <div className="loading">Preparing surface graph…</div>;
|
||||
}
|
||||
|
||||
const extras = (
|
||||
<>
|
||||
<label className="graph-toolbar-field">
|
||||
<span>Search</span>
|
||||
<input
|
||||
className="graph-toolbar-input"
|
||||
type="search"
|
||||
value={searchQuery}
|
||||
onChange={(event) => setSearchQuery(event.target.value)}
|
||||
placeholder="Route, label, or path"
|
||||
/>
|
||||
</label>
|
||||
<label className="graph-toolbar-field">
|
||||
<span>Match</span>
|
||||
<select
|
||||
className="graph-toolbar-select"
|
||||
value={selectedNodeKey ?? ''}
|
||||
onChange={(event) => {
|
||||
const next = event.target.value;
|
||||
if (!next) return;
|
||||
onSelectNode(Number(next));
|
||||
}}
|
||||
>
|
||||
<option value="">Select…</option>
|
||||
{matches.map((match) => (
|
||||
<option key={match.key} value={match.key}>
|
||||
{match.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="graph-toolbar-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={neighborhoodOnly}
|
||||
onChange={(event) => setNeighborhoodOnly(event.target.checked)}
|
||||
/>
|
||||
<span>Neighbors only</span>
|
||||
</label>
|
||||
<label className="graph-toolbar-field graph-toolbar-field-compact">
|
||||
<span>Radius</span>
|
||||
<input
|
||||
className="graph-toolbar-range"
|
||||
type="range"
|
||||
min="1"
|
||||
max="4"
|
||||
step="1"
|
||||
value={radius}
|
||||
disabled={!neighborhoodOnly}
|
||||
onChange={(event) => setRadius(Number(event.target.value))}
|
||||
/>
|
||||
<strong>{radius}</strong>
|
||||
</label>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<SigmaGraph
|
||||
graph={graph}
|
||||
viewKind="surface"
|
||||
selectedNodeKey={selectedNodeKey}
|
||||
onNodeClick={(key) => onSelectNode(Number(key))}
|
||||
searchMatchKeys={matchKeys}
|
||||
toolbarExtras={extras}
|
||||
loading={isLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue