Let me try to sketch out the problem a bit more.
- You've got a surface that you can draw points and lines to, and you know how to make it look how you want it to look.
- You have a data source that provides points to draw, and that data source is changed on the fly.
- You want the surface to accurately reflect the incoming data as closely as possible.
The first question is--what about your situation is slow? Do you know where your delays are coming from? First, be sure you have a problem to solve; second, be sure you know where your problem is coming from.
Let's say your problem is in the size of the data as you imply. How to address this is a complex question. It depends on properties of the data being graphed--what invariants you can assume and so forth. You've talked about storing data in a float[]
, so I'm going to assume that you've got a fixed number of data points which change in value. I'm also going to assume that by '100 or 1000' what you meant was 'lots and lots', because frankly 1000 floats is just not a lot of data.
When you have a really big array to draw, your performance limit is going to eventually come from looping over the array. Your performance enhancement then is going to be reducing how much of the array you're looping over. This is where the properties of the data come into play.
One way to reduce the volume of the redraw operation is to keep a 'dirty list' which acts like a Queue<Int>
. Every time a cell in your array changes, you enqueue that array index, marking it as 'dirty'. Every time your draw method comes back around, dequeue a fixed number of entries in the dirty list and update only the chunk of your rendered image corresponding to those entries--you'll probably have to do some scaling and/or anti-aliasing or something because with that many data points, you've probably got more data than screen pixels. the number of entries you redraw in any given frame update should be bounded by your desired framerate--you can make this adaptive, based on a metric of how long previous draw operations took and how deep the dirty list is getting, to maintain a good balance between frame rate and visible data age.
This is particularly suitable if you're trying to draw all of the data on the screen at once. If you're only viewing a chunk of the data (like in a scrollable view), and there's some kind of correspondence between array positions and window size, then you can 'window' the data--in each draw call, only consider the subset of data that is actually on the screen. If you've also got a 'zoom' thing going on, you can mix the two methods--this can get complicated.
If your data is windowed such that the value in each array element is what determines whether the data point is on or off the screen, consider using a sorted list of pairs where the sort key is the value. This will let you perform the windowing optimization outlined above in this situation. If the windowing is taking place in both dimensions, you most likely will only need to perform one or the other optimization, but there are two dimensional range query structures that can give you this as well.
Let's say my assumption about a fixed data size was wrong; instead you're adding data to the end of the list, but existing data points don't change. In this case you're probably better off with a linked Queue-like structure that drops old data points rather than an array, because growing your array will tend to introduce stutter in the application unnecessarily.
In this case your optimization is to pre-draw into a buffer that follows your queue along--as new elements enter the queue, shift the whole buffer to the left and draw just the region containing the new elements.
If it's the /rate/ of data entry that's the problem, then use a queued structure and skip elements--either collapse them as they're added to the queue, store/draw every n
th element, or something similar.
If instead it's the rendering process that is taking up all of your time, consider rendering on a background thread and storing the rendered image. This will let you take as much time as you want doing the redraw--the framerate within the chart itself will drop but not your overall application responsiveness.