{#if loading && !nodes.length} {:else}
{#each allRelTypes as type} {/each} {#each links as link} {@const s = endpoint(link.source)} {@const t = endpoint(link.target)} {#if s?.x != null && t?.x != null && s?.y != null && t?.y != null && activeRelTypes.has(link.type) && visibleNodeIds.has(s.id) && visibleNodeIds.has(t.id)} {@const vs = linkVisualState(link)} {@const dx = t.x - s.x} {@const dy = t.y - s.y} {@const len = Math.max(Math.hypot(dx, dy), 1)} {@const tr = nodeRadius(t) + 3} {@const ex = t.x - (dx / len) * tr} {@const ey = t.y - (dy / len) * tr} {link.type} {#if vs.emphasized && view.k >= 0.7} {link.type} {/if} {/if} {/each} {#each nodes as node (node.id)} {#if node.x != null && node.y != null && visibleNodeIds.has(node.id)} {@const r = nodeRadius(node)} {@const op = nodeOpacity(node)} {@const isFocus = hoveredId === node.id || selectedId === node.id} {@const isMatch = matchedIds !== null && matchedIds.has(node.id)} onNodePointerDown(e, node)} onpointerenter={() => (hoveredId = node.id)} onpointerleave={() => (hoveredId = null)} onkeydown={(e) => e.key === 'Enter' && selectNode(node)} ondblclick={() => rerootTo(node)} > {#if isFocus || isMatch} {/if} {#if view.k >= 0.8 || isFocus || isMatch || op === 1 && focusIds !== null} {node.slug} {/if} {/if} {/each}
scroll to zoom · drag background to pan · drag nodes · click to inspect · double-click to re-root
{/if}