Skip to main content

The problem it solves

The full telemetry dataset contains approximately 17,500 records covering one year of 3-minute interval data. Fetching all records at page load results in a 2–5 MB payload and a 2–5 second wait before the chart renders. During that time, the user sees a blank screen. Progressive loading reduces the time to first meaningful render to under 500 ms while still delivering the full dataset.

Stage 1: Instant aggregated render

On tab load, the dashboard fetches daily aggregated data — one data point per day rather than one per 3-minute interval:
This returns 30–365 rows totalling approximately 50 KB. Charts render immediately with this coarse data. The loadingStage state transitions from 'initial' to 'streaming'.

Stage 2: Background streaming

After Stage 1, a second useEffect fires (triggered by loadingStage === 'streaming') and begins fetching raw records in chunks:
For each chunk:
  1. New raw records are merged into state alongside the aggregated data
  2. Charts re-render progressively, replacing aggregated points with raw points for that date range
  3. A progress badge in the bottom-right corner shows completion percentage
  4. The UI remains fully interactive throughout — the user can change date ranges, select lamps, or apply filters while streaming continues
A 100 ms delay between chunks (LOADING_CONFIG.STREAM_DELAY) prevents the browser from being overwhelmed.

When streaming is skipped

If the total record count exceeds 50,000, Stage 2 exits immediately and sets loadingStage = 'complete'. This prevents browser memory exhaustion on very large date ranges.

Chart downsampling

Even after full streaming, charts are limited to 300 data points (LOADING_CONFIG.MAX_CHART_POINTS). If more points are loaded, the chart step-samples — takes every Nth record — to stay within this limit. This prevents rendering lag without visibly affecting chart shape for trend analysis.

Performance results

The loading state machine

Three states govern the loading lifecycle, defined as the LoadingStage type in lib/types.ts:

Which tabs use progressive loading

Configuration constants

All tuneable values live in lib/constants.ts under LOADING_CONFIG: