A high-performance streaming time series visualizer for raylib with multiple trace support.
- Multiple overlapping traces
- Ring buffer for efficient memory usage
- Build-up and scroll behavior
- Multiple line modes (Raw, Linear, Spline)
- Auto-scaling with smooth transitions
explicit RLTimeSeries(Rectangle aBounds, size_t aWindowSize = 500);Parameters:
aBounds- The rectangle defining the chart's position and sizeaWindowSize- Maximum number of samples to keep per trace
enum class RLTimeSeriesLineMode {
Raw, // Simple connected line segments
Linear, // Points with linear connecting lines
Spline // Points with Catmull-Rom spline interpolation
};struct RLTimeSeriesTraceStyle {
Color mColor{80, 180, 255, 255};
float mLineThickness{2.0f};
RLTimeSeriesLineMode mLineMode{RLTimeSeriesLineMode::Linear};
bool mShowPoints{false};
float mPointRadius{3.0f};
bool mVisible{true};
};struct RLTimeSeriesChartStyle {
// Background
bool mShowBackground{true};
Color mBackground{20, 22, 28, 255};
// Grid and axes
bool mShowGrid{true};
Color mGridColor{40, 44, 52, 255};
int mGridLinesX{8};
int mGridLinesY{4};
bool mShowAxes{true};
Color mAxesColor{70, 75, 85, 255};
// Padding inside bounds
float mPadding{10.0f};
// Y-axis scaling
bool mAutoScaleY{true};
float mMinY{-1.0f};
float mMaxY{1.0f};
float mAutoScaleMargin{0.1f}; // 10% margin above/below data range
// Spline quality (pixels per segment)
float mSplinePixels{4.0f};
// Smooth scale transitions
bool mSmoothScale{true};
float mScaleSpeed{4.0f};
};| Method | Description |
|---|---|
setBounds(Rectangle aBounds) |
Set the chart bounds |
setStyle(const RLTimeSeriesChartStyle &aStyle) |
Apply a style configuration |
setWindowSize(size_t aWindowSize) |
Set maximum samples per trace |
getWindowSize() const |
Get window size |
| Method | Description |
|---|---|
addTrace(const RLTimeSeriesTraceStyle &aStyle = {}) |
Add a new trace (returns index) |
setTraceStyle(size_t aIndex, const RLTimeSeriesTraceStyle &aStyle) |
Set trace style |
setTraceVisible(size_t aIndex, bool aVisible) |
Show/hide a trace |
clearTrace(size_t aIndex) |
Clear samples from a trace |
clearAllTraces() |
Clear all trace data |
getTraceCount() const |
Get number of traces |
getTraceSampleCount(size_t aIndex) const |
Get sample count for a trace |
| Method | Description |
|---|---|
pushSample(size_t aTraceIndex, float aValue) |
Add one sample to a trace |
bool pushSamples(size_t aTraceIndex, const std::vector<float>& rValues) |
Add multiple samples. Returns false if rValues is empty or aTraceIndex is invalid. |
| Method | Description |
|---|---|
update(float aDt) |
Update scale transitions (call each frame) |
draw() const |
Draw the chart |
| Method | Description |
|---|---|
getBounds() const |
Get current bounds |
getPlotArea() const |
Get the actual plot area (minus padding) |
#include "raylib.h"
#include "RLTimeSeries.h"
#include <cmath>
int main() {
InitWindow(1200, 400, "Time Series Example");
SetTargetFPS(60);
// Define chart area
Rectangle lBounds = {20, 20, 1160, 360};
// Create chart with 500 sample window
RLTimeSeries lChart(lBounds, 500);
// Configure style
RLTimeSeriesChartStyle lStyle;
lStyle.mBackground = Color{20, 22, 28, 255};
lStyle.mShowGrid = true;
lStyle.mGridLinesX = 10;
lStyle.mGridLinesY = 4;
lStyle.mAutoScaleY = true;
lChart.setStyle(lStyle);
// Add a trace
RLTimeSeriesTraceStyle lTraceStyle;
lTraceStyle.mColor = Color{80, 200, 255, 255};
lTraceStyle.mLineThickness = 2.0f;
lTraceStyle.mLineMode = RLTimeSeriesLineMode::Linear;
size_t lTraceIdx = lChart.addTrace(lTraceStyle);
float lTime = 0.0f;
while (!WindowShouldClose()) {
float lDt = GetFrameTime();
lTime += lDt;
// Generate sample (sine wave with noise)
float lSample = sinf(lTime * 2.0f) + 0.1f * sinf(lTime * 20.0f);
// Push sample to trace
lChart.pushSample(lTraceIdx, lSample);
// Update
lChart.update(lDt);
BeginDrawing();
ClearBackground(RAYWHITE);
// Draw chart
lChart.draw();
EndDrawing();
}
CloseWindow();
return 0;
}Display multiple overlapping traces:
RLTimeSeries lChart(lBounds, 1000);
// Add trace 1 (blue)
RLTimeSeriesTraceStyle lStyle1;
lStyle1.mColor = BLUE;
lStyle1.mLineThickness = 2.0f;
size_t lTrace1 = lChart.addTrace(lStyle1);
// Add trace 2 (red)
RLTimeSeriesTraceStyle lStyle2;
lStyle2.mColor = RED;
lStyle2.mLineThickness = 2.0f;
size_t lTrace2 = lChart.addTrace(lStyle2);
// In update loop, push to both traces
lChart.pushSample(lTrace1, lSineValue);
lChart.pushSample(lTrace2, lCosineValue);Simple connected segments, fastest rendering:
lTraceStyle.mLineMode = RLTimeSeriesLineMode::Raw;Points with linear interpolation:
lTraceStyle.mLineMode = RLTimeSeriesLineMode::Linear;
lTraceStyle.mShowPoints = true;
lTraceStyle.mPointRadius = 3.0f;Smooth curves using Catmull-Rom interpolation:
lTraceStyle.mLineMode = RLTimeSeriesLineMode::Spline;
// Adjust quality in chart style
lChartStyle.mSplinePixels = 3.0f; // Lower = smootherThe chart uses a ring buffer for efficient memory usage:
// Window size determines how many samples are kept
lChart.setWindowSize(1000); // Keep last 1000 samples
// Push samples as they arrive
while (lDataAvailable) {
float lValue = lGetNextSample();
lChart.pushSample(lTraceIdx, lValue);
}
// Old samples are automatically discarded when window is fullToggle trace visibility:
// Hide trace
lChart.setTraceVisible(lTraceIdx, false);
// Show trace
lChart.setTraceVisible(lTraceIdx, true);