Creating an Organizational Chart using C#: Part 2

In part 1 of this series, I went over how to actually establish the tree layout that would be used to create an organizational chart using C#.

Now that we have established we have a loaded tree structure, we simply need to build the chart itself.

To simplify the explanation of this process, I have broken the drawing out into two sections.

The first section, BuildBlock, simply builds the actual block which will have each Employee's name and title information, with a background color and a small black border around the outside. By breaking this out of the process, it makes the code much easier to follow.

I will comment inline in the method, so here is the code for BuildBlock:

// Get the height and widths of each text blob, with their fonts, so we can center them in the block
namewidth = (int)gfx.MeasureString(employee.Name, fontname).Width;
nameheight = (int)gfx.MeasureString(employee.Name, fontname).Height;
titlewidth = (int)gfx.MeasureString(employee.Title, fonttitle).Width;
titleheight = (int)gfx.MeasureString(employee.Title, fonttitle).Height;

// Establish a padding bitmap, which will have 10 pixels around the entire image
// Padding makes it look much better so they are not cramping and allows for easier drawing of lines
Bitmap padding = new Bitmap(width + 20, height + 20);

// Make a graphics object from the padding bitmap
Graphics padGfx = Graphics.FromImage(padding);

// Center the image in the padding canvas
padGfx.DrawImage(canvas, new Point(10, 10));

// Flush the output to the bitmap
padGfx.Flush();
return padding;
}

The second aspect of drawing the tree, is drawing the entire tree itself. If you look at the structure of a tree, each tree is really a branch, even the tree itself, from the larger aspect.

To make the drawing logical and much easier to understand, if you break each grouping into a branch, you can then apply logic to each branch and traverse upwards until your tree is complete.

The aptly named BuildBranch is the real "meat" of our organizationl chart builder, so without further ado, here is the recursive code:

private Bitmap BuildBranch(Employee Manager)
{
// In each case of BuildBranch, Manager is really just the parent of all the children

// Get the block of the manager
Bitmap manager = BuildBlock(Manager);

// Now do the same for each child, obtaining a list of all Bitmap children
List<Bitmap> children = new List<Bitmap>();
foreach (Employee reportee in Manager.Children)
{
children.Add(BuildBlock(reportee));
}

int canvasWidth = 0;
int canvasHeight = 0;

// Figure out your final heights and widths
// Do not forget that a branch could also just be a single employee without any children,
// essentially rendering a branch the same as a block
if (children.Count > 0)
{
foreach (Bitmap child in children)
{
canvasHeight += child.Height;
canvasWidth = manager.Width;
}
// Always increase the height by the manager
canvasHeight += manager.Height;
}
else
{
canvasWidth = manager.Width;
canvasHeight = manager.Height;
}

// Create the bitmap to the correct size
Bitmap result = new Bitmap(canvasWidth, canvasHeight);

// Now create a Graphics object from that bitmap
Graphics gfx = Graphics.FromImage(result);

// If the manager has children, then you want to draw a line down to connect the branches below
if (children.Count > 0)
{
Graphics liner = Graphics.FromImage(manager);
liner.DrawLine(new Pen(Brushes.Black, 2), new Point(manager.Width / 2, 90), new Point(manager.Width / 2, 100));
liner.Flush();
}

// Draw a line from the center of the manager up (to connect to the next block)
Graphics liner = Graphics.FromImage(manager);
liner.DrawLine(new Pen(Brushes.Black, 2), new Point(manager.Width / 2, 0), new Point(manager.Width / 2, 10));
liner.Flush();