Inicia integrar Anzograph

This commit is contained in:
Oxy8
2026-02-13 16:39:41 -03:00
parent f3db6af958
commit 343055b7dd
13 changed files with 666 additions and 20472 deletions

View File

@@ -6,6 +6,7 @@ export default function App() {
const rendererRef = useRef<Renderer | null>(null);
const [status, setStatus] = useState("Loading node positions…");
const [nodeCount, setNodeCount] = useState(0);
const uriMapRef = useRef<Map<number, { uri: string; label: string; isPrimary: boolean }>>(new Map());
const [stats, setStats] = useState({
fps: 0,
drawn: 0,
@@ -14,7 +15,7 @@ export default function App() {
ptSize: 0,
});
const [error, setError] = useState("");
const [hoveredNode, setHoveredNode] = useState<{ x: number; y: number; screenX: number; screenY: number } | null>(null);
const [hoveredNode, setHoveredNode] = useState<{ x: number; y: number; screenX: number; screenY: number; index?: number } | null>(null);
const [selectedNodes, setSelectedNodes] = useState<Set<number>>(new Set());
// Store mouse position in a ref so it can be accessed in render loop without re-renders
@@ -39,19 +40,21 @@ export default function App() {
(async () => {
try {
setStatus("Fetching data files…");
const [nodesResponse, primaryEdgesResponse, secondaryEdgesResponse] = await Promise.all([
const [nodesResponse, primaryEdgesResponse, secondaryEdgesResponse, uriMapResponse] = await Promise.all([
fetch("/node_positions.csv"),
fetch("/primary_edges.csv"),
fetch("/secondary_edges.csv"),
fetch("/uri_map.csv"),
]);
if (!nodesResponse.ok) throw new Error(`Failed to fetch nodes: ${nodesResponse.status}`);
if (!primaryEdgesResponse.ok) throw new Error(`Failed to fetch primary edges: ${primaryEdgesResponse.status}`);
if (!secondaryEdgesResponse.ok) throw new Error(`Failed to fetch secondary edges: ${secondaryEdgesResponse.status}`);
const [nodesText, primaryEdgesText, secondaryEdgesText] = await Promise.all([
const [nodesText, primaryEdgesText, secondaryEdgesText, uriMapText] = await Promise.all([
nodesResponse.text(),
primaryEdgesResponse.text(),
secondaryEdgesResponse.text(),
uriMapResponse.ok ? uriMapResponse.text() : Promise.resolve(""),
]);
if (cancelled) return;
@@ -90,6 +93,21 @@ export default function App() {
edgeData[idx++] = parseInt(parts[1], 10);
}
// Parse URI map if available
if (uriMapText) {
const uriLines = uriMapText.split("\n").slice(1).filter(l => l.trim().length > 0);
for (const line of uriLines) {
const parts = line.split(",");
if (parts.length >= 4) {
const id = parseInt(parts[0], 10);
const uri = parts[1];
const label = parts[2];
const isPrimary = parts[3].trim() === "1";
uriMapRef.current.set(id, { uri, label, isPrimary });
}
}
}
if (cancelled) return;
setStatus("Building spatial index…");
@@ -182,9 +200,9 @@ export default function App() {
frameCount++;
// Find hovered node using quadtree
const node = renderer.findNodeAt(mousePos.current.x, mousePos.current.y);
if (node) {
setHoveredNode({ ...node, screenX: mousePos.current.x, screenY: mousePos.current.y });
const nodeResult = renderer.findNodeIndexAt(mousePos.current.x, mousePos.current.y);
if (nodeResult) {
setHoveredNode({ x: nodeResult.x, y: nodeResult.y, screenX: mousePos.current.x, screenY: mousePos.current.y, index: nodeResult.index });
} else {
setHoveredNode(null);
}
@@ -331,7 +349,22 @@ export default function App() {
boxShadow: "0 2px 8px rgba(0,0,0,0.5)",
}}
>
({hoveredNode.x.toFixed(2)}, {hoveredNode.y.toFixed(2)})
{(() => {
if (hoveredNode.index !== undefined && rendererRef.current) {
const vertexId = rendererRef.current.getVertexId(hoveredNode.index);
const info = vertexId !== undefined ? uriMapRef.current.get(vertexId) : undefined;
if (info) {
return (
<>
<div style={{ fontWeight: "bold", marginBottom: 2 }}>{info.label}</div>
<div style={{ fontSize: "10px", color: "#8cf", wordBreak: "break-all", maxWidth: 400 }}>{info.uri}</div>
{info.isPrimary && <div style={{ color: "#ff0", fontSize: "10px", marginTop: 2 }}> Primary (rdf:type)</div>}
</>
);
}
}
return <>({hoveredNode.x.toFixed(2)}, {hoveredNode.y.toFixed(2)})</>;
})()}
</div>
)}
</>