While Quartz provides excellent drawing capabilities for making graphs and charts, it's generally not fast enough to plot real-time changing data sets. In this situation OpenGL can be used to draw the line segments.
To the
UI-Elements library, I've added a simple class
GLPlot that handles plotting of a constantly changing floating point data set using OpenGL. All you need to do is provide a pointer to the data buffer and then display the provided view in your application.
The following methods are provided by GLPlot:
- (id) init;
- (UIView*) view;
- (void) setDataBuffer:(float*)buffer;
- (void) setViewport:(CGRect)window;
- (void) plotFrom:(int)start to:(int)stop;
If for example, your program has a data buffer containing 1000 points, you would likely use the following code in a ViewController to initialize the GLPlot:
#import <UI-Elements/GLPlot.h>
...
@property (nonatomic, strong) GLPlot* plot;
@property (nonatomic) float* buf;
....
int numPoints = 1000;
self.buf = malloc(numPoints * 2 * sizeof(float));
self.plot = [[GLPlot alloc] init];
[self.plot setDataBuffer: self.buf];
The buffer should contains a series of vertices X1, Y1, X2, Y2, etc... Hence, a buffer containing 50 data points is described by 100 floating point numbers.
The visible data window (a.k.a. viewport) can be set by providing a CGRect of any size whose origin is the lower left point of the plot. Such is to say the following call...
[self.plot setViewport: CGRectMake(-300.0f, -100.0f, 600.0f, 200.0f)];
... will plot the data on a X axis from -300.0 to 300.0 and a Y axis from -100.0 to 100.0.
You must specify the range of vertices in the data buffer to be plotted. If possible, it would be best to set the range to cover only data points which are known to lie inside the viewport.
Note: the range is in terms of vertices, not buffer indexes. So the following call...
[self.plot plotFrom: 100 to: 330];
... would indicate the 230 data points described from dataBuffer[200] and dataBuffer[659] should be plotted. If you instruct the GLPlot to plot data from memory which has not been properly allocated a segmentation fault is
very likely to occur.
Finally, to display the plot in your application, you just need to insert the view provided by the GLPlot:
[self.view addSubview: [self.plot view]];
The view has a transparent background, so you can place it on top of whatever background you like (for example, gridlines). It is configured to update at 30 fps to reflect the state of the provided data buffer. The foreground color of the graph line is settable through ColorScheme, similarly to other classes in UI-Elements.