isual Studio comes with a huge number of pre-built components and controls, including controls for entering and displaying text, letting the user pick options and make choices, displaying values graphically, interacting with databases, displaying dialogs, and containing and arranging other controls. But it comes with surprisingly few controls for displaying graphical data. If you don't want to shell out big bucks for a third-party graphing control, you're pretty much stuck drawing your own pictures on a PictureBox.
Fortunately, drawing graphs isn't all that hard. Mostly it's a matter of drawing lines or boxes to connect some data points. The only really tricky details involve translating data values to and from the pixel coordinate system used to draw on the control.
Before getting to those issues, however, the following section describes the GreatGraph control's features.
Figure 1 shows a form containing two GreatGraph controls that demonstrate many of the control's features.
|Figure 1. This form uses two GreatGraph controls to display four sets of data.|
The control on the left in the figure shows three sets of data superimposed on one another.
- The first set is displayed as a bar graph with yellow bars outlined in red. This data set also displays the points' maximum, minimum, and average values using horizontal dotted blue lines. In the figure, the user's mouse is over the data point (-3, 3.025675) so the control is displaying an appropriate tooltip. This data set also allows users to click and drag to change a point's Y coordinate so the mouse cursor has changed to an up/down arrow.
- The second set of data is rendered as a line graph with thick black dashed lines. This data set also displays tooltips but does not allow users to move data points.
- The third set of data is displayed with the blue rectangles filled with white. This data set displays tooltips. It allows the user to change both X and Y coordinates so when the mouse moves over a data point the cursor changes to an up/down/left/right arrow cursor.
To represent these three different sets of data, the control uses three DataSeries objects. It also contains three additional DataSeries objects to represent the axes it displays. The X and Y axes are drawn in dark gray while the angled axis is drawn in green. These DataSeries objects are configured to display tick marks and labels. They don't interact with the user so they don't display tooltips or allow the user to move the data points.
The GreatGraph control on the right in Figure 1 draws a green line graph connecting a sequence of points that do not form a simple function y = F(x). It also contains a set of additional DataSeries objects to draw the silver circles showing different distances from the origin.
There are tons of other features you could add to a graphing control. You could add other kinds of labels (text placed arbitrarily on the graph), titles, keys, and legends. The GreatGraph control doesn't provide these for two reasons. First, it's next to impossible to predict all the possible combinations that you might want to display using all of these additional elements.
Second, it's easy enough to add most of these above rather than within the control. For example, you can place a legend in a simple Label sitting above the GreatGraph control. While you can add these features if you want, I think you'll find that the control is complicated enough as it is.
GreatGraph Control Architecture
The GreatGraph control's basic design is relatively straightforward. The control holds a list of DataSeries objects. Each DataSeries object contains an array of PointF objects that represent data coordinates. While the GreatGraph control ties everything together, the DataSeries class does most of the control's heavy lifting.
The DataSeries class provides a Draw method that causes the object to draw itself on a Graphics object's surface. The class also provides properties that determine the data's appearance when drawn. For example, properties determine whether the control draws its data as a bar graph, a line graph, or a series of points. Properties also control the pens and brushes used to draw the data, whether the result includes tick marks or labels, and whether users are allowed to click and drag to change the data points' X or Y coordinates.
This architecture makes repainting simplewhen it needs to repaint itself, the GreatGraph object simply loops through its DataSeries objects telling each to draw itself.
That's the basic idea, anyway. Most of the particulars are not terribly complicated but there are a lot of them. The following sections provide more detail about how the control draws graphs, provides tooltips, and lets users click and drag data points around. You can download Visual Basic or C# versions of the example program to see all of the details and to watch the code in action.