Using the .NET Chart API to add sparklines to your MVC site
In my last post, I introduced sparklines and showed you how to generate them using the Google Chart API. Using an external API may not be appropriate for all applications, so here is a way to generate the sparkline using the .NET Chart API.
Over at the Better Dashboards Blog, they provide some sample code for calling the chart API. The following shows how to make it reusable for your MVC application.
First, we'll create a custom ActionResult to return the image for our sparkline:
public class SparklineResult : FileResult { IEnumerable<float> samples; int SparklineWidth; int SparklineHeight; public SparklineResult(int width, int height, IEnumerable<float> samples) : base("image/png") { this.samples = samples; this.SparklineHeight = height; this.SparklineWidth = width; } protected override void WriteFile(HttpResponseBase response) { var sparklineImage = GetSparkLineImage(samples, SparklineWidth, SparklineHeight); response.ContentType = "image/png"; response.BinaryWrite(sparklineImage); } private static byte[] GetSparkLineImage(IEnumerable<float> samples, int width, int height) { var chart = new Chart(); var series = new Series(); chart.Series.Add(series); // Sparklines use the 'Spline' chart type to show a smoother trend with a line chart series.ChartType = SeriesChartType.Spline; // Since the line is the only thing you see on the chart, you might want to // increase its width. Interestingly, you need to set the BorderWidth property // in order to accomplish that. series.BorderWidth = 2; // Add samples to the series int i = 0; foreach (var sample in samples) { i++; // Add 5 to the sample so line does not get cut off at the bottom of the image chart.Series[0].Points.AddXY(DateTime.Now.AddDays(i), sample + 5); } // Start hiding both sets of axes, labels, gridlines and tick marks var chartArea = new ChartArea(); chart.ChartAreas.Add(chartArea); chartArea.AxisX.LabelStyle.Enabled = false; chartArea.AxisY.LabelStyle.Enabled = false; chartArea.AxisX.MajorGrid.Enabled = false; chartArea.AxisY.MajorGrid.Enabled = false; chartArea.AxisX.MajorTickMark.Enabled = false; chartArea.AxisY.MajorTickMark.Enabled = false; chartArea.AxisX.LineWidth = 0; chartArea.AxisY.LineWidth = 0; chartArea.AxisY.Minimum = 0; // Add an extra 5 pixels since the samples were adjusted up by 5 // this prevents the line from being truncated chartArea.AxisY.Maximum = 105; // Re-adjust the size of the chart to reduce unnecessary white space chart.Width = width; chart.Height = height; // Get bytes of PNG image var s = new MemoryStream(); chart.SaveImage(s, ChartImageFormat.Png); s.Position = 0; return s.ToArray(); } }
Next, we'll utilize the SparklineResult in a controller. The controller will serve the image data for the sparkline back to the calling page.
public class ChartController : Controller { public ActionResult Sparkline(int width, int height, string samples) { return new SparklineResult(width, height, (from s in samples.Split(',') select float.Parse(s)).ToArray()); } }
Next, we'll create a HTML helper method to generate the img tag which will fetch the image from our controller.
public static MvcHtmlString DrawSparkline(this HtmlHelper helper, int width, int height, IEnumerable<int> plotData) { string sparkUrl = "<img src='/chart/sparkline?width={0}&height={1}&samples={2}'/>"; string sparkLine = String.Format(sparkUrl, width, height, String.Join(",", plotData)); return MvcHtmlString.Create(sparkLine); }
Now we can call the helper method from our Razor template:
@Html.DrawSparkline(70, 20, new int[14] { 1, 4, 2, 6, 20, 30, 1, 23, 14, 2, 41, 2, 33, 21 })
Which produces the following sparkline:
You can download my sample project that puts it all together. This includes both the Google API & .NET API methods.