We’ve been working like mad to get a (very) functional prototype of our new system running at work, which is why my posts have been rather sparse lately. We’re doing interesting things, just not much that I can talk about. Today is different though, I actually have something useful to share!
My current task revolves around rendering charts. I’ve previously used a variety of charting libraries, mostly recently Telerik and dotnetCharting, but we wanted to go a different route this time. Neither was a good fit for ASP.NET MVC the last time I looked. So, I thought I’d pick up one of the many handy JavaScript charting libraries and be done with it. Unfortunately, that didn’t pan out. Flot is simply not flexible enough for my needs. jqPlot was about the same. Yeah, you can extend either of them, but I wanted something I could customize with less work (basically I wanted more built-in options). I also looked at the Google solution, but that’s the exact opposite of flexible since it renders as a non-interactive image. After lots of wailing around, I gave up on the JavaScript route and concluded that none of them are really mature.
I briefly considered Silverlight before deciding that I should see what Flash had available. Much to my surprise, I found a great little charting library that works well enough with .NET: FusionCharts Free! Out of all the charting APIs I’ve used over the years, this has quickly become my favorite. You just feed in an XML definition of what the graph should look like, and it renders it. It offers a slew of options, too, making it a good fit for what I needed.
Sadly the samples all deal with ASP.NET WebForms and not with ASP.NET MVC. The same approach works, but I wanted something cleaner. I decided to create an HtmlHelper extension that would allow me to build a FusionChart with a fluent interface. Despite my aversion to fluent interfaces, I do think there are times where they make sense, and I think control builders for MVC are a good fit. My approach when I make a fluent interface is simple: anything that’s required is a parameter of the head method in the fluent chain. All other optional settings are exposed as fluent methods. An alternative is to accept some sort of “settings” object that exposes all the settings as properties, and while this does allow for the same terse inline configuration, it’s less readable to me than the fluent version.
Anyway, let’s look at the usage of this API. You would call it from your view like any other HtmlHelper:
Html.FusionCharts().Column2D(Model.Data, 415, 247, d => d.TotalSales) .Label(d => d.ShortName) .Hover(d => d.LongName) .XAxisLabel("Widgets") .YAxisLabel("Sales") .DecimalPrecision(2) .UseDynamicSuffixes(true) .NumberPrefix("$") .Action(d => Html.BuildUrlFromExpression<WidgetController>(c => c.ViewWidget(d=>d.Id)))
Html.FusionCharts() returns a helper class that exposes methods for creating the various chart types (for now, I’ve only implemented the 2D column chart, but plan to do others). Column2D is the head of the fluent chain and returns a FusionChartBuilder<T>:
/// <summary> /// Gets a fusion chart builder that will create a 2D bar chart. /// </summary> /// <typeparam name="T">The type of the data items.</typeparam> /// <param name="data">The items to bind to the chart.</param> /// <param name="width">Width in pixels.</param> /// <param name="height">Height in pixels.</param> /// <param name="getValue">Delegate that extracts the numerical value from a data item.</param> /// <returns></returns> public FusionChartBuilder<T> Column2D<T>( IEnumerable<T> data, int width, int height, Func<T, double> getValue) { return new FusionChartBuilder<T>(mHtmlHelper, mUrlHelper.Content("~/Charts/FCF_Column2D.swf"), data, getValue, width, height); }
The builder enables me to configure options on my charts cleanly from within my view. I’m not exposing all the FusionChart options yet (and probably won’t), but so far I can control the chart labels, the tooltip that’s shown when you hover over a bar, the format of the numbers, and I can even add a link to each bar, enabling users to “drill-down” into the data or navigate to a corresponding details page.
Time is short, so I’m not going to get any further into the code today, but I will in a future post. For now, feel free to tell me how you love/hate fluent APIs or what a brilliant/dumb developer I am for using Flash from ASP.NET.