{#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}