Introduction
This article presents an example to create interactive charts on the browsers using
the "ASP.NET charting"
tool with "Image Maps". It also demonstrates how to add the same charts in PDF documents by re-using the same code.
Background
When developing web applications, you can easily find many tools that help to add charts to your applications. Most of these tools use client side JavaScript.
Among these tools, you should easily notice the "jQuery based charting
libraries" and the Telerik Charting Library.
They either base the charts on HTML5 canvases or SVG Graphics.
These charting libraries can bring highly advanced and interactive charts to web browsers. But sometimes common requirements in your projects may include:
- Creating interactive charts on web browsers;
- Displaying the same charts in other places, such as in Microsoft Word or PDF documents.
It is not an easy task to re-use the same client side JavaScript code to meet both requirements. In this article, I will try to meet both requirements using the
ASP.NET Charting
tool with Image Maps in MVC. Different from the previously mentioned
charting libraries, the charts generated by the ASP.NET
charting tool are images. These image charts can be as beautiful as charts created by other libraries, but they have limited ability to support user interactions on browsers.
The example application in this article is to demonstrate to you the following:
- When used with Image Maps, the charts created by the
ASP.NET charting
tool should provide some reasonable user interaction capabilities.
The ASP.NET charting
tool enables us to easily generate the "Image Maps" associated with the charting images. You will find out how to generate
the Image Maps and associate them with the charting images from the example application.
- Besides showing the charts on browsers, the example application will also show you how to use the exact same code to create charts to be embedded in PDF documents.
The attached simple MVC 2 web application is developed in Visual Studio 2010. Since it is developed as an MVC application, I will assume readers have some basic knowledge of how to use MVC.
As shown in the Solution Explorer, the main building blocks of this web application are the following:
- The Models\BrowserShareModel.cs file is the application's data model. We will use the data in this data model to generate the charts using the
ASP.NET charting tool.
- The two files MyChartBase.cs and BrowserShareChart.cs in the Utilities\ChartUtilities
folder implement the classes that will be used to generate the charts. MyChartBase.cs defines the basic look and feel of the charts, while BrowserShareChart.cs
inherits from the
MyChartBase
class and overrides some methods to insert data to the charts. - The Utilities\PdfUtility.cs file implements a simple class to generate a PDF document using the chart images created by the above two classes.
- The Controllers\HomeController.cs file is this simple MVC application's controller and the Views\Home\Index.aspx file is the application's view.
In this article, I will first introduce you to the application's data model. I will then introduce the utility classes and show how to use these classes in the MVC application.
The Data Model
The application's data model is implemented in the Models\BrowserShareModel.cs file:
using System.Collections.Generic;
using System.IO;
using MVCChart.Utilities.ChartUtilities;
namespace MVCChart.Models
{
public class BrowserInformation
{
public string Name { get; set; }
public double Share { get; set; }
public string Url { get; set; }
public string ToolTip
{
get
{
return Name + " " + Share.ToString("#0.##%");
}
}
}
public class BrowserShareChartData
{
public string Title { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public List<BrowserInformation> ShareData { get; set; }
public MemoryStream ChartImageStream()
{
var chart = new BrowserShareChart(this);
return chart.GetChartImage(Width, Height);
}
public string ChartImageMap(string name)
{
var chart = new BrowserShareChart(this);
return chart.GetChartImageMap(Width, Height, name);
}
}
public class BrowserShareRepository
{
public static BrowserShareChartData GetBrowserShares()
{
var chartData = new BrowserShareChartData()
{
Title = "Browser usage on Wikipedia October 2011",
Width = 450,
Height = 300,
ShareData = new List<BrowserInformation>()
};
chartData.ShareData.Add(new BrowserInformation()
{
Name = "IE",
Share = 0.342,
Url = "http://en.wikipedia.org/wiki/Internet_Explorer"
});
chartData.ShareData.Add(new BrowserInformation()
{
Name = "Firefox",
Share = 0.236,
Url = "http://en.wikipedia.org/wiki/Firefox"
});
chartData.ShareData.Add(new BrowserInformation()
{
Name = "Chrome",
Share = 0.206,
Url = "http://en.wikipedia.org/wiki/Google_Chrome"
});
chartData.ShareData.Add(new BrowserInformation()
{
Name = "Safari",
Share = 0.112,
Url = "http://en.wikipedia.org/wiki/Safari_(web_browser)"
});
chartData.ShareData.Add(new BrowserInformation()
{
Name = "Other",
Share = 0.104,
Url = null
});
return chartData;
}
}
}
This file implements three classes:
BrowserInformation
defines a data point in the chart.- The
BrowserShareChartData
class defines the data for the chart. It holds a reference of a "List
"
of "BrowserInformation
" objects to create the chart "Series".
It also defines the width, height, and the title of the chart. - The
BrowserShareRepository
class instantiates a BrowserShareChartData
object and assigns it some real data about the browser market share in October 2011 that
I got from Wikipedia.
In this article, I will show you how to create a chart using the
ASP.NET Charting
tool to visualize the browser market share information. The chart will be shown on the browser and in a PDF document. When shown in a browser, I will
add tooltips and hyperlinks to the chart using an Image Map to make the chart
interactive. You should be able to create more advanced interactions using Image Maps, but I will
only show you how to add tooltips and hyperlinks to keep this article simple.
The Charting Utility Classes
"Utilities\ChartUtilities\MyChartBase.cs" defines the basic look and feel of the charts in the example application:
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Web.UI.DataVisualization.Charting;
namespace MVCChart.Utilities.ChartUtilities
{
public class MyChartBase
{
protected List<Series> ChartSeriesData { get; set; }
protected string ChartTitle { get; set; }
public MemoryStream GetChartImage(int width, int height)
{
var chart = InitiateChart(width, height);
chart.RenderType = RenderType.BinaryStreaming;
var ms = new MemoryStream();
chart.SaveImage(ms, ChartImageFormat.Png);
return ms;
}
public string GetChartImageMap(int width, int height, string mapName)
{
var chart = InitiateChart(width, height);
chart.RenderType = RenderType.ImageMap;
chart.SaveImage(Stream.Null);
return chart.GetHtmlImageMap(mapName);
}
protected virtual void AddChartTitle()
{
ChartTitle = null;
}
protected virtual void AddChartSeries()
{
ChartSeriesData = new List<Series>();
}
private Chart InitiateChart(int width, int height)
{
var chart = new Chart();
chart.Width = width;
chart.Height = height;
chart.BorderSkin.BackColor = System.Drawing.Color.Transparent;
chart.BorderSkin.PageColor = System.Drawing.Color.Transparent;
chart.BackColor = System.Drawing.Color.FromArgb(211, 223, 240);
chart.BorderlineDashStyle = ChartDashStyle.Solid;
chart.BackSecondaryColor = System.Drawing.Color.White;
chart.BackGradientStyle = GradientStyle.TopBottom;
chart.BorderlineWidth = 1;
chart.Palette = ChartColorPalette.BrightPastel;
chart.BorderlineColor = System.Drawing.Color.FromArgb(26, 59, 105);
chart.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
chart.AntiAliasing = AntiAliasingStyles.All;
chart.TextAntiAliasingQuality = TextAntiAliasingQuality.Normal;
AddChartTitle();
if (ChartTitle != null)
{
chart.Titles.Add(CreateTitle());
}
chart.Legends.Add(CreateLegend());
AddChartSeries();
foreach (var series in ChartSeriesData)
{
chart.Series.Add(series);
}
chart.ChartAreas.Add(CreateChartArea());
return chart;
}
private Title CreateTitle()
{
return new Title()
{
Text = ChartTitle,
ShadowColor = System.Drawing.Color.FromArgb(32, 0, 0, 0),
Font = new System.Drawing.Font("Trebuchet MS", 10, FontStyle.Bold),
ShadowOffset = 3,
ForeColor = System.Drawing.Color.FromArgb(26, 59, 105)
};
}
private Legend CreateLegend()
{
return new Legend()
{
Docking = Docking.Bottom,
Alignment = StringAlignment.Center,
BackColor = System.Drawing.Color.Transparent,
Font = new System.Drawing.Font(new System.Drawing.FontFamily("Trebuchet MS"), 8),
LegendStyle = LegendStyle.Row
};
}
private ChartArea CreateChartArea()
{
var area = new ChartArea()
{
Name = ChartTitle,
BackColor = System.Drawing.Color.Transparent,
};
area.AxisX.IsLabelAutoFit = true;
area.AxisX.LabelStyle.Font =
new System.Drawing.Font("Verdana,Arial,Helvetica,sans-serif",
8F, FontStyle.Regular);
area.AxisX.LineColor = System.Drawing.Color.FromArgb(64, 64, 64, 64);
area.AxisX.MajorGrid.LineColor = System.Drawing.Color.FromArgb(64, 64, 64, 64);
area.AxisX.Interval = 1;
area.AxisY.LabelStyle.Font =
new System.Drawing.Font("Verdana,Arial,Helvetica,sans-serif",
8F, FontStyle.Regular);
area.AxisY.LineColor = System.Drawing.Color.FromArgb(64, 64, 64, 64);
area.AxisY.MajorGrid.LineColor = System.Drawing.Color.FromArgb(64, 64, 64, 64);
return area;
}
}
}
If you create an object of this class and call the GetChartImage
method, you will get the
MemoryStream
of an empty chart image.
If you call the GetChartImageMap
method, you will get the empty HTML string of the Image Map
associated with the chart image. I will not go to the details of how to use the
ASP.NET Charting
tool here. But if you are interested, you can take a look at the article ASP.NET MVC Chart Control.
It is the place where I got started to use the ASP.NET
Charting tool in the MVC environment.
To visualize your data in a meaningful chart, we need to create a new class that inherits from the MyChartBase
class and override the AddChartSeries
and AddChartTitle
methods to add the data to the chart. The following is the class to create the browser market share chart in this article:
using System.Collections.Generic;
using System.Web.UI.DataVisualization.Charting;
using MVCChart.Models;
namespace MVCChart.Utilities.ChartUtilities
{
public class BrowserShareChart : MyChartBase
{
private BrowserShareChartData chartData;
public BrowserShareChart(BrowserShareChartData chartData)
{
this.chartData = chartData;
}
protected override void AddChartTitle()
{
ChartTitle = chartData.Title;
}
protected override void AddChartSeries()
{
ChartSeriesData = new List<Series>();
var series = new Series()
{
ChartType = SeriesChartType.Pie,
BorderWidth = 1
};
var shares = chartData.ShareData;
foreach (var share in shares)
{
var point = new DataPoint();
point.IsValueShownAsLabel = true;
point.AxisLabel = share.Name;
point.ToolTip = share.Name + " " +
share.Share.ToString("#0.##%");
if (share.Url != null)
{
point.MapAreaAttributes = "href=\"" +
share.Url + "\"";
}
point.YValues = new double[] { share.Share };
point.LabelFormat = "P1";
series.Points.Add(point);
}
ChartSeriesData.Add(series);
}
}
}
By inheriting from the MyChartBase
class, the BrowserShareChart
class inherits the styles defined in MyChartBase
.
To add the data for visualization:
- It overrides the
AddChartTitle
method to add a title to the chart. - It also overrides the
AddChartSeries
method to add the
"Series" data to the chart.
You should pay some attention to the AddChartSeries
method. Besides adding chart data, it also adds tooltips and hyperlinks
to the chart "Series". If an object
of BrowserShareChart
is properly initiated with the correct data, you can call the GetChartImage
method inherited from the base class
to obtain the chart image in the form of a MemoryStream
.
You can also call GetChartImageMap
in the base class to obtain the Image Map
that adds the tooltips and hyperlinks to your chart in the browsers. I will show you how to use this Image Map later
in this article.
The PdfUtility Class
In order to show you how to add charts in PDF documents, I created a small class in the "Utilities\PdfUtility.cs" file:
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace MVCChart.Utilities
{
public class PdfUtility
{
public static MemoryStream GetSimplePdf(MemoryStream chartImage)
{
const int documentMargin = 10;
var pdfStream = new MemoryStream();
var pdfDocument = new Document(PageSize.LETTER);
pdfDocument.SetMargins(documentMargin, documentMargin,
documentMargin, documentMargin);
PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDocument, pdfStream);
Image image = Image.GetInstance(chartImage.GetBuffer());
image.SetAbsolutePosition(documentMargin
, pdfDocument.PageSize.Height - documentMargin - image.ScaledHeight);
pdfDocument.Open();
pdfDocument.Add(image);
pdfDocument.Close();
pdfWriter.Flush();
return pdfStream;
}
}
}
This small class is used to generate a very simple PDF document. If you pass
the MemoryStream
for the chart generated by the BrowserShareChart
class
to the GetSimplePdf
method, it will return to you a MemoryStream
of a PDF document with the chart in it. This class uses iTextSharp to create the PDF document. You can download
iTextSharp from its web site. I am not going to the details of how to use iTextSharp here.
If you are interested, you can take a look at the article Export Tabular Data in PDF Format
Through the Web. It has detailed instructions on how to use iTextSharp.
Now that we have completed the data model and the utility classes, let us take a look at how we can use them in our MVC application.
The MVC Controller
The MVC application's controller is implemented in the Controllers\HomeController.cs file:
using System.Web.Mvc;
using MVCChart.Models;
using MVCChart.Utilities;
namespace MVCChart.Controllers
{
[HandleError]
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
var chartData = BrowserShareRepository.GetBrowserShares();
return View(chartData);
}
[HttpGet]
public FileResult GetChart()
{
var chartData = BrowserShareRepository.GetBrowserShares();
return File(chartData.ChartImageStream().GetBuffer()
, @"image/png", "BrowserShareChart.png");
}
[HttpGet]
public FileResult GetPdf()
{
var chartData = BrowserShareRepository.GetBrowserShares();
var chartStream = chartData.ChartImageStream();
return File(PdfUtility.GetSimplePdf(chartStream).GetBuffer()
, @"application/pdf", "BrowserShareChart.pdf");
}
}
}
The controller of this MVC application has three "Action" methods:
- The
Index
method is the application's entry point that brings up the view page of the web application. - The
GetChart
method calls the application's data model and indirectly calls GetChartImage
in the BrowserShareChart
class to obtain the MemoryStream
of the browser market share chart image.
It then passes the chart image to the browser as a FileResult
. - The
GetPdf
method goes one step further. When it obtains the MemoryStream
of the browser market share chart image, it passes it to the GetSimplePdf
method in the PdfUtility
class
to obtain the PDF document. It also passes the PDF document to the browser as
a "FileResult
".
The MVC View
The MVC application's view is implemented in the "Views\Home\Index.aspx" file:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MVCChart.Models.BrowserShareChartData>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Index</title>
<link href="<%=Url.Content("~/content/Site.css") %>" rel="stylesheet" type="text/css" />
</head>
<body>
<div style="display: inline-block">
<div>
<img usemap="#ChartImageMap" src="<%= Url.Action("GetChart", "Home") %>"
alt="Asp.Net Charting generated image"
style="width:450px;height:300px;border-width:0px;" />
<% Response.Write(Model.ChartImageMap("ChartImageMap"));%>
</div>
<div style="margin-right: 20px; text-align: right">
<a href="<%= Url.Action("GetPdf", "Home") %>">Get the chart in Pdf</a>
</div>
</div>
</body>
</html>
In this simple view page, I added the following:
- The chart image in an "
img
" tag and its "Image Map". - I also added a link to call the
GetPdf
method in the controller to download the PDF document.
To add an Image Map to the chart, we can simply write the
Image Map created by the GetChartImageMap
method in the BrowserShareChart
class
next to the img
tag where we put our chart image. Associating the
Image Map with the chart image is pretty simple, but you need to make sure that the name of the
Image Map matches the usemap
attribute of the image.
Run the Application
We have completed this example application, we can now test run it. When the application starts, the browser market share pie-chart is shown in the web browser.
If we move the mouse over the chart, the "image map" takes effect, and we can see the tooltip that we specified in the chart.
If we click on one of the sections in the chart, the corresponding web page is shown according to the hyperlink that we put in the chart.
Click the back button on the browser to go back to our web page and click on the "Get the chart in PDF" link, a PDF document is generated
with the same chart as the one shown in the browser.
Points of Interest
- This article presented an example to create interactive charts on browsers using the
ASP.NET charting
tool with Image Maps. It also demonstrated how to add the same charts in PDF documents by re-using the same code.
- There are many charting libraries and most of them can create more efficient and more interactive charts on browsers than the
ASP.NET charting tool.
But they are dedicated to creating charts on browsers, so it is difficult to use the same charts on other places.
Of course, if your only intention is to display your charts on browsers, I would recommend you use client side charting libraries like the
Telerik Charting Library, which can definitely provide better interactivity and possibly better efficiency.
- When used with Image Maps, the
ASP.NET charting
tool can create reasonably interactive charts on browsers. In this example, I only showed you how to add tooltips and hyperlinks to charts, but you can definitely
make the charts more interactive by working on
MapAreaAttributes
when you add the chart
"Series".
You can also add client side JavaScript to make your charts more interactive. - Besides creating charts beyond browsers, the
ASP.NET charting tool
has some other advantages. In any foreseeable future, we can safely assume that images are always supported anywhere on any Operating System, so your charts should always
be supported if you create them as images.
- Another advantages to using ASP.NET charting
is that it is now included in the default deployment of the .NET Framework. If .NET
is your primary working environment, you do not need to add any extra DLLs in your projects to create your desired charts.
- If you are developing a desktop application, you should also be able to use the
ASP.NET charting tool
to create charts and display them in your application.
- Although the example is developed as an MVC application, you can easily use the same principle to add charts in more traditional ASP.NET applications.
- I hope you like my postings and I hope this article can help you one way or the other.
History
- 12/13/2011: First revision.