Skip to content

Add interactive labels to timeline, semantic, and map frames - #61

Merged
Korede-TA merged 10 commits into
mainfrom
claude/kb-viz-node-labels
Jul 6, 2026
Merged

Add interactive labels to timeline, semantic, and map frames#61
Korede-TA merged 10 commits into
mainfrom
claude/kb-viz-node-labels

Conversation

@Korede-TA

@Korede-TA Korede-TA commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Zoom-dependent node labels on Map, Semantic, and Timeline frames — labels appear on hover/select at any zoom, and ambient labels progressively reveal as you zoom in
  • Grid-based label declutter (pickVisibleLabels) prevents overlapping labels by spatial thinning; timeline uses viewport-aware 1D horizontal bucketing
  • Pick disambiguation menu (PickMenu) — clicking overlapping nodes on Map or Timeline shows a popup listing all nodes at that point, with click/shift-click to select
  • Adaptive timeline axis ticks — axis markers now scale from 5000-year to 1-day intervals based on visible range and viewport width, replacing the static year-step approach
  • deriveLabel utility extracts readable labels from node properties (title → label → source → text → id fallback) with configurable truncation

Test plan

  • Map frame: zoom in past threshold, verify labels appear without overlap; zoom out, verify they thin
  • Semantic frame: same label behavior
  • Timeline frame: zoom in/out, verify axis tick labels adapt granularity (years → months → days) and never cluster
  • Timeline frame: verify node labels thin to ~12 visible in viewport
  • Click overlapping dots on Map or Timeline — verify disambiguation popup appears
  • Shift-click in popup adds to selection; regular click replaces selection
  • Popup dismisses on Escape, click outside, or pan/zoom

🤖 Generated with Claude Code

Each frame tracks zoom via onViewStateChange and conditionally renders
a TextLayer above the scatter layer:

- SemanticFrame: labels appear for all nodes at zoom ≥ 3.5 (UMAP space);
  always visible for selected (red) and hovered (yellow) nodes
- MapFrame: labels appear for all nodes at geo zoom ≥ 6 (city level);
  always visible for selected/hovered; TextLayer rendered below ScatterplotLayer
  so dots stay on top
- TimelineFrame: labels appear when zoomed ≥ 3 stops in from the initial
  fit zoom (≈8× zoom-in); always visible for selected/hovered; uses
  monospace font to match the tick axis style

All frames use a dark translucent background rect (background: true) on
each label for legibility, and truncate text to 22-28 chars depending on
the frame.

https://claude.ai/code/session_01EefsLVhEiLxKsJzAbgC1CQ
@netlify

netlify Bot commented Jun 23, 2026

Copy link
Copy Markdown

Deploy Preview for akb-suruleredotdev ready!

Name Link
🔨 Latest commit c0e33e8
🔍 Latest deploy log https://app.netlify.com/projects/akb-suruleredotdev/deploys/6a4c34553c0cde000814318e
😎 Deploy Preview https://deploy-preview-61--akb-suruleredotdev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

claude and others added 9 commits June 24, 2026 03:55
…lict

Keep both zoom tracking (node labels) and brushShiftRef (shift-additive
brush select from PR #60) in TimelineFrame state declarations.

https://claude.ai/code/session_01EefsLVhEiLxKsJzAbgC1CQ
Ambient (non-selected) labels truncated more aggressively:
- Semantic: 25 → 12 chars
- Map: 28 → 14 chars
- Timeline: 22 → 11 chars

Selected/hovered nodes keep longer labels (20/22/20 chars) so focused
nodes remain readable.

https://claude.ai/code/session_01EefsLVhEiLxKsJzAbgC1CQ
- Ambient labels truncated to 8 chars; selected/hovered get 14 chars
- Labels no longer filter data by zoom — all points stay in the layer;
  visibility is controlled by alpha in getColor/getBackgroundColor
  (0 when hidden, full value when visible)
- transitions: { getColor: 250, getBackgroundColor: 250 } gives a smooth
  250ms fade when labels appear/disappear on zoom or selection change

https://claude.ai/code/session_01EefsLVhEiLxKsJzAbgC1CQ
Previously maxLen was only applied to the node.text fallback path.
Title and label properties (used by document-level nodes) returned the
full raw string, so long book/document titles were never truncated.

https://claude.ai/code/session_01EefsLVhEiLxKsJzAbgC1CQ
deriveLabel now accepts an optional nodesById map. When provided and
the node has a parent_id, the label is formatted as:
  'Parent titl… · chunk text…'
(parent truncated to 10 chars, chunk to the requested maxLen)

Canvas frames (Semantic, Map, Timeline) pass nodesById so chunk-level
nodes carry document context in their canvas labels. Callers that don't
pass nodesById (SummaryFrame, TextFrame, etc.) are unaffected.

https://claude.ai/code/session_01EefsLVhEiLxKsJzAbgC1CQ
…ticks

Grid-based spatial thinning prevents label overlap across Map, Semantic,
and Timeline frames. PickMenu lets users disambiguate clicks on overlapping
nodes. Timeline ticks now adapt granularity (years→months→days) to the
visible viewport range.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces static yearTicks with a step table (5000y down to 1 day) that
picks the finest interval fitting a per-viewport-width tick budget.
Axis markers now thin out at wide zoom and fill in as you zoom into
narrower time ranges.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Korede-TA
Korede-TA merged commit fbc470a into main Jul 6, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants