Title: Make a sunburst chart in C#, Part 4
The previous post showed how to make a sunburst chart with curved text. This example extends that one so it can draw multi-line text.
The previous post used the DrawTextOnArc method to draw curved text. The text is a distance radius from the chart's center, and it is centered between the angles min_theta and max_theta. This example uses the DrawTextOnArc method to draw each of the lines of text needed for multiline descriptions.
The first step, however, is to represent multiline text in the XML data. The earlier examples use XML element names for the text. Unfortunately XML does not allow you to place line breaks inside an element name.
To work around that, I decided to add an optional Text attribute to the elements. If the attribute is present, the program uses its value for the node's text. If the value is missing, the program uses the element's name.
Within the Text value, the \n sequence indicates a new line. That's my convention, not an XML convention. You can actually embed newlines within XML text, this just seemed simpler.
The DrawSunburstChild method uses the following code to find a node's text.
// Get the node's text.
string text = node.Name;
if (node.Attributes["Text"] != null)
text = node.Attributes["Text"].Value;
This code sets variable text equal to the node's name. It then checks whether the node has the Text attribute and, if it does, it updates the text variable to hold its value.
After it finds the node's text, the program calls the following new DrawNodeTextInWedge method to draw a node's text.
// Draw multi-line text in a wedge.
private void DrawNodeTextInWedge(Graphics gr, Brush brush,
Font font, string text, float cx, float cy,
double min_theta, double max_theta, float mid_r)
{
// Get the node's text.
string[] separators = { @"\n" };
string[] lines = text.Split(separators, StringSplitOptions.None);
// See how tall each line should be.
float hgt = font.Height * 0.8f;
// Calculate the minimum and maximum radii,
// and the change in radius per line dr.
float min_r = mid_r - (lines.Length - 1) * hgt / 2f;
float max_r = min_r + (lines.Length - 1) * hgt;
float dr = (max_r - min_r) / (float)(lines.Length - 1);
// Draw the lines of text.
float radius = max_r;
for (int i = 0; i < lines.Length; i++)
{
DrawTextOnArc(gr, brush, font, lines[i],
cx, cy, min_theta, max_theta, radius);
radius -= dr;
}
}
The method first splits the text into lines. It calculates the font's height and multiplies it by the fudge factor 0.8. It does that to make the lines of text sit closer together because the font's normal height is a big larger than necessary for this kind of caption. You may need to fiddle with this value a bit to get the best result for your font.
Next the code calculates the smallest and largest radii where the lines of text should be drawn. The picture on the right shows the relationships between the three radii used here. The value max_r is the distance from the center of the chart to the first line of text, min_r is the distance from the center to the last line of text, and mid_r is the distance from the center to the middle of the wedge.
The picture on the right uses three lines of text, but in general the node could have any number. For example, in the picture at the top of the post the wedge "All Kinds of Vegetables" uses three lines and the wedge "Dessert Choices" uses two lines. Note that the wedge "Various Sports" also uses three lines but the middle line is blank.
After it calculates the minimum and maximum radii, the code calculates the distance dr between adjacent lines. The code then loops through the lines of code and calls DrawTextOnArc to draw each of the lines at the appropriate radius.
That's all I'm going to say about sunburst charts, for a while at least. There are plenty of enhancements you could make to the basic program. For example, I tried experimenting with colors that blend between parent and child nodes. It looked okay if the colors were related (blending from dark green to light green), but it looked terrible with unrelated colors (blending from red to blue).
It might also be nice to automatically size the font. Rotated text looks fuzzy or pixelated when the font is complicated and the characters are small. This example uses 10-point bold Arial, which is about the smallest font that looks nice. You could make the program adjust the font size to fit the available wedges.
Download the example to experiment with it and to see additional details.
|