Skip to content

perf(analysis): virtualize the LOG viewer (smooth scroll/select on huge logs)#25

Merged
oahsiao merged 1 commit into
mainfrom
perf/ana-virtualized-viewer
Jun 23, 2026
Merged

perf(analysis): virtualize the LOG viewer (smooth scroll/select on huge logs)#25
oahsiao merged 1 commit into
mainfrom
perf/ana-virtualized-viewer

Conversation

@oahsiao

@oahsiao oahsiao commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Problem

After the earlier single-insert fix (#23) opening got fast, but an ~82k-line log still kept ~250k DOM nodes. Scrolling and especially drag-selecting text lagged badly — selecting across content-visibility lines forces the browser to lay them all out (it could effectively lock up the renderer).

Fix: virtualize the viewer

Render only the lines near the viewport — a fixed-height window with top/bottom spacer divs holding the off-screen height. The rest never enter the DOM, so the node count stays ~constant regardless of file size.

Everything that assumed every line was in the DOM is routed through the lines array + a windowed anaLineEl(idx):

  • scroll-to-line, current line, bookmarks, find highlights (CSS Custom Highlight API), copy, line click;
  • minimap / level markers are still scanned across all lines once (~45 ms for 82k).

content-visibility is removed. The viewer is now nowrap (long lines scroll horizontally) because virtualization needs a fixed line height — so the word-wrap toggle button and its code/i18n are removed.

Also: PgUp/PgDn focus fix

Paging stopped working after the first press because re-rendering the window destroyed whatever held keyboard focus. Now the scroller (#anaScroll, which is never rebuilt) is the focus target (tabindex="-1", focused on open and on click), so PgUp/PgDn/Home/End/arrows keep working.

Result

On a real 82,576-line log: opening stays fast, scrolling and text selection are smooth, and selection no longer locks up. DOM nodes drop from ~250k to ~a few hundred.

Testing

  • npm test → 4/4.
  • Verified on the reporter's 82k-line log: scroll, drag-select + copy, Copy button, Ctrl+F (next/prev), bookmarks (Ctrl+F2, F2/Shift+F2), line click, minimap click/drag, level chips, zoom (Ctrl +/-), and repeated PgUp/PgDn.

Note

Word-wrap is intentionally removed (a fixed line height is required for virtualization); long lines scroll horizontally instead.

Opening was already fixed (single-insert), but an 80k-line log still kept
~250k DOM nodes, so scrolling and especially drag-selecting text lagged hard
(selecting across content-visibility lines forces them all to lay out, which
could lock up the renderer).

Render only the lines near the viewport: a fixed-height window with top/bottom
spacer divs holding the off-screen height; the rest never enter the DOM. The
features that assumed every line was in the DOM are routed through the lines
array + a windowed anaLineEl(idx): scroll-to-line, current line, bookmarks,
find highlights, copy, line click. Markers for the minimap/levels are still
scanned across all lines once (~45ms for 82k). content-visibility is removed.

The viewer is now always nowrap (long lines scroll horizontally) because
virtualization needs a fixed line height, so the word-wrap toggle button and
its code/i18n are removed.

PgUp/PgDn focus fix: the scroller (#anaScroll), which is never rebuilt, is the
keyboard-focus target (tabindex=-1, focused on open and on click), so paging
and arrows keep working after the window re-renders.

Measured on a real 82,576-line log: opening stays fast and scroll/selection
are smooth; selection no longer locks up.
@oahsiao oahsiao merged commit fbd3914 into main Jun 23, 2026
5 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.

1 participant