A few months ago, to get an idea of what contributed to the
size of Mono libraries I wrote a
small Treemap
visualizer using Moonlight:

Moonlight's assemblies; area represents the codesize.
You
can browser
the code or get a copy from our AnonSVN repository.
There are a couple of tools here:
My Treemap is not very ambitious, and it is nowhere as
complete as the new Treemap control that is part of the open
source Silverlight Toolkit. But it was a fun learning
experience for me.
Reusable Engine
I did not really know where we would use this control, on
the web or on the desktop when I started. So I split the
actual engine that does the heavy lifting from the actual
chrome for the application.
This is why I ended up with a Silverlight user interface
and a Gtk# user interface. This idea in general might be
useful for other developers as well.
The Custom Control
The custom control is very simple, it is called
TreemapRenderer and derives
from UserControl. The code overwrites two
methods: MeasureOverride
and ArrangeOverride. These methods are used to
allow the control to participate in the Silverlight layout
system (for example, the control can be embedded in a table
that can auto-stretch). Silverlight invokes
your MeasureOverride to find out the desired size
that you control would like to consume:
public class TreemapRenderer : UserControl {
protected override Size MeasureOverride(Size availableSize)
[...]
protected override Size ArrangeOverride(Size finalSize)
[...]
}
Silverlight will invoke your
control's ArrangeOverride to layout its contents
once it has determined the size that the control will use.
This is where my TreemapRenderer lays out its
contents.
This code renders an actual region on the treemap, I like
the C# 3.0 initializer syntax for the text created:
public void SetRegion (Rect newRegion)
{
region = newRegion;
content.Children.Clear ();
content.Width = region.Width;
content.Height = region.Height;
if (caption != ""){
int max;
string formatted = MakeCaption (caption, out max);
double w = region.Width * 1.60;
double s = w / max;
var text = new TextBlock () {
FontSize = s,
Text = formatted,
Foreground = new SolidColorBrush (Color.FromArgb (255, 0x5c, 0x5c, 0x5c))
};
Canvas.SetTop (text, (region.Height-text.ActualHeight)/2);
Canvas.SetLeft (text, (region.Width-text.ActualWidth)/2);
content.Children.Add (text);
}
Rect emptyArea = region;
Squarify (emptyArea, root.Children);
Plot (root.Children);
}
To provide feedback to the user, I change the background
color of the treemap on enter/leave. I use anonymous two
anonymous methods, one for MouseEnter, one
for MouseLeave.
Notice that state is shared by these two blocks of code
using C# variable capturing. A key feature of the language:
bool inside = false;
host.MouseEnter += delegate {
host.Background = new SolidColorBrush (Colors.Yellow);
if (text != null)
text.Foreground = new SolidColorBrush (Colors.Black);
inside = true;
};
host.MouseLeave += delegate {
host.Background = transparentBrush;
if (text != null)
text.Foreground = borderBrush;
inside = false;
};
One thing that proved very useful was the ability to
zoom-into an area. If you click on an assembly, you will get
a rendering of the code size used by a type; If you click on
that, you get a method breakdown on a class:

drill-down into mscorlib's sizes.
To transition, I added a cute animation where I render the
new image and animate it from the area occupied in the larger
view into the final size. This is the code that queues the
animation:
// Render a child
void Clicked (Node n)
{
// This is the child rendered, configure it to its final size
TreemapRenderer c = new TreemapRenderer (n, n.Name);
Size ns = new Size(region.Width, region.Height);
c.Measure (ns);
c.Arrange(region);
//
// Scale it and position on the spot that it currently
// occupies on the screen
//
var xlate = new TranslateTransform () {
X = n.Rect.X,
Y = n.Rect.Y };
var scale = new ScaleTransform () {
ScaleX = n.Rect.Width / region.Width,
ScaleY = n.Rect.Height / region.Height };
c.RenderTransform = new TransformGroup { Children = { scale, xlate } };
c.Opacity = 0.5;
content.Children.Add (c);
activeChild = c;
//
// Animate this to its final location
//
TimeSpan time = TimeSpan.FromSeconds (0.3);
var s = new Storyboard () {
Children = {
Animate (time, xlate, "X", 0),
Animate (time, xlate, "Y", 0),
Animate (time, scale, "ScaleX", 1.0),
Animate (time, scale, "ScaleY", 1.0),
Animate (time, c, "Opacity", 1.0),
}};
s.Begin ();
}
// Helper method;
static Timeline Animate (TimeSpan time, DependencyObject target, string path, double to)
{
var animation = new DoubleAnimation () {
Duration = time,
To = to
};
Storyboard.SetTarget (animation, target);
Storyboard.SetTargetProperty (animation, new PropertyPath (path));
return animation;
}
The Silverlight Application
Using the control is fairly simple, but since it loads a
large XML files (feel free to change this to use a web
service) I use the downloader and a callback to render the
control.
private void Application_Startup(object sender, StartupEventArgs e)
{
[...]
var webclient = new WebClient();
webclient.DownloadStringCompleted += delegate (object sender2, DownloadStringCompletedEventArgs ee){
try {
RootVisual.Dispatcher.BeginInvoke(() => LoadNodesFromString(ee.Result));
}
catch (Exception ex) {
main.BackButton.Content = ex.ToString();
}
};
webclient.DownloadStringAsync(new Uri("../mscorlib.xml", UriKind.Relative));
}
The actual creation of the control happens
in LoadNodesFromString:
void LoadNodesFromString(String s)
{
// Use Size for the area.
Node n = LoadNodes(s, "Size", "Extra");
while (n.Children.Count == 1)
n = n.Children[0];
treemap = new TreemapRenderer(n, "");
Grid.SetColumn(treemap, 0);
Grid.SetRow(treemap, 1);
main.grid.Children.Add(treemap);
}
Building a Gtk# Out-of-Browser Client
The above works great for Silverlight, but I like my
application on the desktop, so I created a Gtk# version of
it.
Moonlight provides a Gtk# widget that can be embedded into
C# desktop applications. This is what it looks like when
running on the desktop. I know this screenshot is not too
exciting as I did not do much with the Gtk+ side of things:

Gtk# is rendering, seriously.
The core of embedding Moonlight as a Gtk# widget is very
simple, here it is:
using Moonlight.Gtk;
using Moonlight;
public static void Main(string[] args)
{
n = LoadNodes (args [0], "Size", "Foo");
Gtk.Application.Init ();
MoonlightRuntime.Init ();
// My container window.
Gtk.Window w = new Gtk.Window ("Foo");
w.DeleteEvent += delegate {
Gtk.Application.Quit ();
};
w.SetSizeRequest (width, height);
// The Moonlight widget that will host my UI.
MoonlightHost h = new MoonlightHost ();
// Add Moonlight widget, show window.
w.Add (h);
w.ShowAll ();
// Make it pretty, skip all levels that are just 1 element
while (n.Children.Count == 1)
n = n.Children [0];
// Render
TreemapRenderer r = new TreemapRenderer (n, "");
Size available = new Size (width, height);
r.Measure (available);
r.Arrange (new Rect (0, 0, width, height));
// This informs the widget which widget is the root
h.Application.RootVisual = r;
Gtk.Application.Run ();
}
There are Visual Studio and MonoDevelop solutions on the
SVN for folks to try out.
You can
also try
a sample live on the web.