- RealtimeChart composable with Canvas-based rendering - TieredBuffer: 3-tier ring buffer (5min full-rate, 10min @10Hz, 45min @1Hz) for 1h data support with ~5MB footprint - LodDecimator: MEAN / MIN_MAX / MIN_MAX(default) / LTTB render-time decimation - AxisRenderer: X/Y axis with INSIDE/BESIDE/HIDDEN label modes, T0-relative timestamps, scientific notation - SignalRenderer: clipRect-bounded path rendering with LoD - ChartTheme: Material3-compatible dynamic theming (light/dark) - package: dev.dtrentin.chart Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.3 KiB
4.3 KiB
chart-realtime
What This Is
Standalone KMP module (Android-first) providing a high-performance Compose-based real-time line chart for sensor data visualization. Renders N simultaneous signals at 200Hz+ using Canvas with FIFO circular buffers and Level-of-Detail decimation. Packaged as a dependency consumable by any Android/KMP app.
Core Value
Android developers can plot multiple high-frequency sensor signals (200Hz+) on a single chart without dropping frames or overloading the device.
Current State
| Attribute | Value |
|---|---|
| Type | Application (library module) |
| Version | 0.0.0 |
| Status | Initializing |
| Last Updated | 2026-05-20 |
Requirements
Core Features
- Multi-signal real-time rendering — N signals on same chart, each with own color/style, added/removed dynamically
- FIFO circular buffer — pre-allocated, lock-free write (data thread) / safe read (render thread), maxBufferSeconds configurable by caller
- Level-of-Detail decimation — min/max envelope per pixel column when buffer > pixel width; O(pixels) render cost regardless of buffer size
- Flexible axis control — X axis: seconds from t0 (T0.FirstSample or T0.Fixed); Y axis: YRange.Auto(padding) or YRange.Fixed(min, max)
- Render rate decoupling — data ingestion at any rate; rendering via withFrameNanos at display refresh rate (throttleable via targetFps param)
- Flow-based API — addSignal(name, flow, config) + manual push(name, timestampMs, value)
Validated (Shipped)
None yet.
Active (In Progress)
None yet.
Planned (Next)
- Phase 1: KMP module scaffold + Gradle config
- Phase 2: CircularBuffer + LodDecimator + unit tests
- Phase 3: RealtimeChartState + Flow integration
- Phase 4: Canvas rendering engine (RenderLoop, AxisRenderer, SignalRenderer)
- Phase 5: Demo Android app (5+ signals at 200Hz)
- Phase 6: Material3 polish + API documentation
Out of Scope
- iOS support (deferred to future milestone)
- Touch interaction / zoom / pan
- SciChart/paid-lib integration
- Network data sources (consumer provides Flow)
Target Users
Primary: Android/KMP developers building sensor dashboards (IoT, medical, industrial)
- Need 200Hz+ real-time plotting
- Want drop-in Compose composable
- Expect Material3 visual consistency
Constraints
Technical Constraints
- KMP commonMain for all rendering logic (Compose Multiplatform Canvas)
- No object allocation in draw loop (pre-allocated FloatArray paths)
- Single draw call per signal (drawLines with FloatArray)
- Lock-free circular buffer (data thread != render thread)
- maxBufferSeconds: caller responsibility, no hard cap enforced by lib
Business Constraints
- Standalone publishable module (Maven local / GitHub Packages)
- No paid/commercial dependencies
Key Decisions
| Decision | Rationale | Date | Status |
|---|---|---|---|
| Canvas custom rendering over existing libs | Vico/MPAndroidChart cannot handle 200Hz+ without axis jumps or FPS drops | 2026-05-20 | Active |
| Render/data rate decoupling via withFrameNanos | 200Hz data != 60fps display; buffer absorbs delta | 2026-05-20 | Active |
| LoD min/max decimation | 1h buffer at 200Hz = 720k pts; screen = ~800px; must reduce O(n)→O(px) | 2026-05-20 | Active |
| maxBufferSeconds configurable, user responsibility | Avoid arbitrary caps; user knows their memory budget | 2026-05-20 | Active |
| Android-first, iOS deferred | Reduce scope, ship faster | 2026-05-20 | Active |
Success Metrics
| Metric | Target | Current | Status |
|---|---|---|---|
| Sustained FPS at 200Hz, 5 signals | ≥55fps | - | Not started |
| Memory per signal per hour at 200Hz | ≤3MB | - | Not started |
| Demo app compiles and runs | Yes | - | Not started |
| API: add signal in ≤3 lines of code | Yes | - | Not started |
Tech Stack
| Layer | Technology | Notes |
|---|---|---|
| Language | Kotlin (KMP) | commonMain + androidMain |
| UI | Jetpack Compose / Compose Multiplatform | Canvas DrawScope |
| Build | Gradle + Version Catalog | Convention plugin if needed |
| DI | None (library, no DI framework) | Consumer wires state |
| Testing | kotlin.test + JUnit5 (androidTest) | Buffer + LoD unit tests |
| Demo | Android app module | 5+ signals, 200Hz simulation |
PROJECT.md — Updated when requirements or context change Last updated: 2026-05-20