2007-03-15
| Table of Contents: |
| Rate This Article: | Add This Article To: |
( Page 1 of 3 )
Peter Aitken continues his detailed saga of developing an XY chart component from scratch.
This is the fourth article in a series that covers all the details of developing a .NET component. By following this process from start to finish, you may learn aspects of .NET development that are not provided in more specialized articles.
The earlier articles have dealt with drawing the chart axes and tick marks, with the data representation in the XYChart class, and with the problem of determining and using the minimum and maximum values for the X and Y data. This may seem like a lot of work with not much to show for it, but we have been building the foundation that everything else will rest on.
In this installment we'll get to some more of the display aspects of the XY chart component, specifically the screen rendering of the axis titles, axis labels, and legend.
The Axis Titles
Each axis will have a single title which is used to describe the data being plotted—pounds, months, profit, etc. Each title, one each for the X axis and the Y axis, will be a property that can be set by the calling program. By now you are probably an expert at adding properties to this component. The two private variables are defined in ctlXY_Chart.vb as shown here. Note that I give them default values, optional but useful for testing.
Private pX_Axis_Title As String = "X axis title" Private pY_Axis_Title As String = "Y axis title"
Then enter the property procedures as follows:
Public Property X_Axis_Title() As String
Get
Return pX_Axis_Title
End Get
Set(ByVal value As String)
pX_Axis_Title = value
End Set
End Property
Public Property Y_Axis_Title() As String
Get
Return pY_Axis_Title
End Get
Set(ByVal value As String)
pY_Axis_Title = value
End Set
End Property
To display the axis titles, I created a procedure named, cleverly enough, DrawAxisTitles(). It will be called from the component's Paint() event procedure and passed the graphics object that Paint() receives. As I explained in Part I of this series, Paint() is called automatically when the component's screen rendering needs to be created or refreshed, so all rendering code must be either in or called from Paint().
Each title will be centered on its respective axis. To control the distance of the title from the axis, I defined two constants and follows (again, in ctlXY_Chart.vb):
Const X_AXIS_TITLE_OFFSET = 20 Const Y_AXIS_TITLE_OFFSET = 30
The X axis title is displayed normally, that is, horizontally. The code is shown here along with this procedure's local variable declarations:
Dim xPos As Integer, yPos As Integer, TextSize As Integer
If Len(pX_Axis_Title) > 0 Then
yPos = Me.Height - MYBOTTOM + X_AXIS_TITLE_OFFSET
' Get the midpoint of the X axis.
xPos = MYLEFT + (Me.Width - MYLEFT - MYRIGHT) / 2
' Get the width of the text to be displayed.
TextSize = e.MeasureString(pX_Axis_Title, f).Width
xPos -= TextSize / 2
e.DrawString(pX_Axis_Title, f, Brushes.Black, xPos, yPos)
End If
Recall that the constants MYBOTTOM, MYLEFT, and MYRIGHT have been defined to specify the distance of the chart axes from the edges of the component. Thus, Me.Height (the height of the component) minus MYBOTTOM gives the vertical position of the X axis, and by adding X_AXIS_TITLE_OFFSET we get the vertical position for the X axis title. This is illustrated in Figure 1, shown below.
Determining the horizontal position of the X axis title is a bit trickier. The coordinate at which the title is drawn is the left end of the text, so to center the title with respect to the axis, the starting X coordinate will depend on the length of the text. Specifically, the text must begin one-half of the text length to the left of the axis center point.
The .NET Framework comes to the rescue with the MeasureString method. It is a member of the Graphics class, and is passed the text to measure and a reference to the font that will be used to display the test. It returns an object of type SizeF that gives the dimensions—the width and height—of the text when displayed. The width measurement is what we need. Here's how the code works. First, get the midpoint of the X axis as follows:
xPos = MYLEFT + (Me.Width - MYLEFT - MYRIGHT) / 2
Then, subtract one-half of the text width. Recall that e is a reference to the Graphics object that will be passed to DrawAxisTitles() by the Paint() procedure.
TextSize = e.MeasureString(pX_Axis_Title, f).Width xPos -= TextSize / 2
Finally, display the X axis title. The variable f refers to the Font object that has been defined elsewhere for display of the axis titles.
e.DrawString(pX_Axis_Title, f, Brushes.Black, xPos, yPos)
The Y axis title introduces an additional complication because we want to display the title rotated 90 degrees so that it is parallel to the axis. Again, the Framework comes to the rescue. The Graphics class which, as we have seen, is the foundation of all screen display, provides for a variety of transformations. This is not the place to go into transformations in any detail! Suffice to say that one of the available transformations is rotation, causing the rendered output to appear rotated at some specified angle to its "normal" appearance.
To implement text rotation, you must create a matrix that defines the rotation. Using the Matrix class, we find that it has a method for just this purpose, RotateAt. You specify the angle of rotation, with positive and negative angles indicating clockwise and counterclockwise rotation, respectively. You also specify the point around which the rotation is to take place—in this case, the position at which the Y axis title is to be displayed.
Thus, we first determine the location of the Y axis title following the same logic as was explained earlier for the X axis title:
xPos = MYLEFT - Y_AXIS_TITLE_OFFSET ' Get the midpoint of the Y axis. yPos = MYTOP + (Me.Height - MYBOTTOM - MYTOP) / 2 ' Get the width of the text to be displayed. TextSize = e.MeasureString(pY_Axis_Title, f).Width ' Adjust the y position accordingly. yPos += TextSize / 2
Next, create a matrix that defines a 90 degree counterclockwise rotation centered on the text location:
Dim m As New Matrix m.RotateAt(-90.0F, New Point(xPos, yPos))
Assign the matrix to the Graphics object and draw the title:
e.Transform = m e.DrawString(pY_Axis_Title, f, Brushes.Black, xPos, yPos)
Finally, reset the transform so it will not be in effect for future graphics operations.
e.Transform.Reset()
The resulting Y axis title display is shown in Figure 2, shown below.

>>> More ASP and .Net Coding Techniques Articles >>> More By Peter Aitken

