A 2D Lite Graph Control with Multiple Plot Support

This is a simple, lightweight 2D graph control that supports multiple plots as well as printing. Why make another graph control? This one gives the user basic functionality which would make a great oscilloscope without a lot of extra features getting in the way. Because it is so small, it’s also a great base from which to develop a more fully featured specialized graph–the very essence of OOP!

Note: It makes use of the MemDC class written by Keith Rule, and downloaded from Codeguru.com.

Overview

Once the control has been created and displayed, the user may run the mouse over it, and the current position and value at that position will be displayed in the upper left-hand corner. The values that are displayed are for the currently selected plot.

In the example above, the selected plot is the “Green Data” plot, which is a sine wave. To select another plot, click its key value on the left-hand side of the graph. This will change the statistics, position, and value accordingly.

The statistics are reported for all the data in the currently selected plot, and will not change unless the underlying data changes.

To “zoom in” on a piece of the plot, draw a rectangle with the mouse by starting in the upper left-hand corner of the desired area, holding down the left mouse button, and moving it to the lower-left hand corner of the area and letting go.

Once the rectangle has been drawn, the axes’ min and max limits will be recalculated and the graph will be redrawn such that the selected area fills the entire graph area.

The user can zoom as many levels down as is realistic for the particular graph in question. The graph stores an “undo” list of zooms, so by drawing a rectangle in reverse (start at bottom right, move to top left), the most recent previous zoom will be restored.

The graph also supports the “locking” of the axes. This is useful if the user would like to update the data, but keep the limits the same as a frame of reference. This also can be used to limit the zoom in one axis only. For example, locking the y axis would effectively zoom in on a narrower and narrower section of the graph. Locking both x and y would disable the zooming feature altogether. To lock an axis, click one of the two icons in the lower left-hand corner. In this example, both are unlocked.

The user also can zoom by manually changing the limits. Clicking on the min or max (in this example, min x = -5.0, max x = 100.0, min y = -10.0, max y = 10.0) will allow the user to type in a number and update the graph.

What else is there? At this point, the plots support two different styles: “line” and “bar.” Above, the “blue data” is of the “bar” style, and the “red data” and “green data” are of the “line” style.

Most parameters are configurable. Take a look at the example below to see.

Documentation

There are two classes that make up this control: CPlotData and CLinePlot. CLinePlot is the main class of the control; it contains a vector of the CPlotData class. You never need to actually manipulate the CPlotData class directly, so you will focus on the CLinePlot class.


BOOL Create(const RECT& rect, UINT uiFlags, CWnd *pwndParent,
UINT uiID);

This is pretty much the standard constructor for a CWnd derived class.


int Add(CString szName, COLORREF crColor, enumPlotStyle nStyle,
FLOATPOINT *pptData, UINT uiPointCount);

This adds a new plot to the control. Note the FLOATPOINT structure; it is basically the same as a POINT structure, except x and y are both floats. It returns the index of the added plot.


int Add(CString szName, COLORREF crColor, enumPlotStyle nStyle,
std::vector<FLOATPOINT> *pvecData);

Same as above, only the data is in a vector instead of an array. It returns the index of the added plot.

void Clear();

Remove all the plots.

int Count();

Returns the number of plots in the graph.

void Print();

Sends a WYSIWYG rendering of the graph to the printer.

bool Remove(int nIndex);

Removes a plot at a specific index. Returns whether or not the operation succeeded.

void Refresh();

Forces the control to be repainted.

int Selected();

Returns the index of the selected plot.

CPlotData &operator[](UINTunIndex);

Gets a reference to the plot at a specific index. This can be used to modify a plot directly.

Examples

In the “OnCreate” or “OnInitDialog”:


m_LinePlot.Create(CRect(0, 0, rcBounds.Width(), rcBounds.Height()),
CHILD | WS_VISIBLE, this, ID_CTRL_LINE_PLOT);

Add a plot to the control:


FLOATPOINT pData3[400];
for (ii=0; ii<400; ii++)
{
pData3[ii].x = (float)(ii);
pData3[ii].y = (float)(cos((float)(ii)/4.0f)*8);
}
COLORREF crColor3 = RGB ( 0, 128, 0);
m_LinePlot.Add(“Green Data”, crColor3, CLinePlot::LpLine, pData3,
101);

See the included example for more details.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read