A Flutter CustomPainter widget that mimics the real-time scrolling waveform display found on clinical ventilator monitors. It was built as part of a Flutter + Arduino ventilator project, where continuous sensor data (airway pressure, tidal volume, flow) needs to be rendered as a live, looping waveform — just like a bedside ICU monitor.
The widget accepts a List of data points and a current index (pointer), then renders a scrolling trace that wraps around the screen as new data arrives — replicating the classic "sweeping line" behaviour of medical monitors.
The index value acts as the write head. As your data loop increments index, the widget erases a small block ahead of the pointer and redraws the waveform behind it, creating the illusion of a continuously scrolling signal. All data is automatically scaled to fit the display area based on minY and maxY.
| Parameter | Type | Default | Description |
|---|---|---|---|
backgroundColor |
Color |
Colors.black |
Canvas background color |
lineColor |
Color |
Colors.redAccent |
Waveform line color |
segmentYColor |
Color |
Colors.white |
Y-axis gridline and label color |
| Parameter | Type | Default | Description |
|---|---|---|---|
dataSet |
List |
required | The data buffer to render (fixed-length list) |
index |
int |
required | Current write position; drives the sweeping pointer |
minY |
double |
1.0 |
Minimum expected data value (used for Y scaling) |
maxY |
double |
0.0 |
Maximum expected data value (used for Y scaling) |
totalSegmentY |
int |
5 |
Number of horizontal gridline divisions on the Y axis |
Tip: Adjusting
minYandmaxYbeyond your actual data range effectively zooms the waveform in or out — useful for emphasising subtle signal variations.
// In your state, maintain a fixed-length buffer and a rolling index:
List<double> _pawDataSet = List.filled(150, 0.0);
int _index = 0;
// On each sensor tick, write new data and advance the pointer:
_pawDataSet[_index] = newPressureValue;
_index = (_index + 1) % _pawDataSet.length;
// Pass them to the widget:
GraphWithPointer(
index: _index,
dataSet: _pawDataSet,
minY: 0.0,
maxY: 80.0,
totalSegmentY: 5,
backgroundColor: Colors.black,
lineColor: Colors.orangeAccent,
segmentYColor: Colors.white,
)- The
dataSetlist should be pre-allocated to a fixed length (e.g.List.filled(150, 0.0)). The widget does not grow or shrink the buffer. shouldRepaintis optimised to only trigger a redraw whenindexchanges, keeping performance smooth during rapid sensor updates.- For historical/trend review (non-scrolling, with a draggable pointer), see the companion
GraphDBWithPointerwidget.
