Using Microsoft's Chart Controls In An ASP.NET Application: Enhancing Charts With AjaxBy Scott Mitchell
Charts are typically used to provide a static snapshot of data. The chart's underlying data might be based on various user inputs, but in the end the chart, once rendered, represents the end of the reporting workflow. However, other scenarios allow for a more interactive user experience. For example, in the Creating Drill Down Reports article we looked at how to configure the Chart control to allow the user to drill into a particular data point. Specifically, the demo contained a column chart showing the number of products in each category in the Northwind database. Clicking on a column whisked the user to a new page that details about the products in that category. Also, in certain situations the data populating the chart might be arriving from a sensor or some other source that is constantly being updated. In that case, we might want a real time chart whose data is periodically (and automatically) refreshed to show the latest data.
Ajax is a set of related techniques used in websites to build more interactive and responsive applications. Microsoft's ASP.NET Ajax Framework offers developers both server- and client-side frameworks for developing Ajax-enabled applications. This article looks at how to use Ajax with the Microsoft Chart controls, focusing on two demos. In the first we'll create a drill down report with a column chart that shows the gross sales per month for a particular category and fiscal year. The user can click on a particular column in the chart to see the breakdown of sales per day in that month on the same page. This breakdown is displayed in an UpdatePanel, and clicking on a column in the chart triggers an asynchronous postback. The other demo looks at using the Timer control to render a real time chart.
Read on to learn more!
Displaying Drill Down Data On The Same Page
The Microsoft Chart controls offer two techniques for building drill down reports:
- By setting the
Urlproperty of the points in the chart, or
- By setting the the Series'
PostBackValueproperty and creating an event handler for the Chart's
Urlproperty causes the Chart control to render not only an
<img>element for the chart, but an image map, as well. An image map defines a set of regions on the map through a series of coordinates and, in this case, associates a URL with each region. When the user clicks within a region, their browser sends them to the associated page.
The second approach - setting the
PostBackValue property and creating a server-side
Click event handler - is similar to the first approach in that
the Chart control renders an image map, but it differs in that when the user clicks on a region within the chart there is a postback. On postback the Chart control raises its
Click event and the
Click event handler executes. This second approach is useful for displaying drill down details on the same page.
The download available for download at the end of the article includes a demo that allows the user to select a category and year from drop-down lists, and then shows the sales per month for the selected year and category in a column chart (see the screen shot below). This sales data chart is almost identical to the one we created in the Adding Statistical Formulas article, the only difference being that this chart is a column chart whereas the one in Adding Statistical Formulas was a line chart.
This chart allows the user to drill down into the sales for a particular month, showing the sales per day for the selected month. To show the monthly sales
breakdown on the same page as the chart we need to configure the chart so that when a column is clicked there is a postback (rather than having the user whisked to a different
page). By default, the Chart control is rendered as a static image. To make it interactive so that a postback occurs when a user clicks on a column we need to set the
PostBackValue property. This property can be defined for a series and indicates value is sent back to the server on postback. If you need to know the Y value
of the column that was clicked, set this property to
#VALY. To get the X value use
#VALX. You can pass both values back, separated by a comma, by
PostBackValue property to
|Displaying X and Y values as Tooltips|
The series that make up a chart can have a tooltip defined for each data point that can include the X and/or Y values using the same placeholders, |
For this demo we need to know the X value of the selected column (the month whose sales data we want to drill into). Therefore, I've set the
#VALX, as the following snippet of declarative markup shows:
Click event fires. We can respond to this event by creating a
Click event handler.
Note the second input parameter - it's of type
ImageMapEventArgs. This type includes an
e.PostBackValue property that contains the value specified
PostBackValue property set in the series (the X value of the clicked column, in this case). So for our demo,
e.PostBackValue contains a value
between 1 and 12, which represents the month of the column that was clicked.
chtCategorySales_Click event handler is a bit long winded and is not central to the discussion of this article, so let me just describe its behavior in prose.
Click event handler starts by running a SQL query to get the sales per day for the selected month (via
e.PostBackValue), year, and category.
(The year and category are selected via a DropDownList control.) A Calendar control is used to highlight the days of the month based on the gross sales that day. If no sales
were made that day then the day is not highlighted. If there were sales, the day is highlighted a color based on the sales. Specifically, there are five different colors,
each representing a different quantity of sales.
Confused yet? Don't worry, a screen shot will clarify things and make up for my less than clear description.
The following screen shot was taken after clicking on the column in the chart corresponding to June. Clicking on that column (or any other one in the chart) causes a postback.
On postback, the Chart's
Click event handler runs and configures the legend and the Calendar based on the sales per day for that month / year / category.
This drill down data gives the user a quick and meaningful grasp of how the sales for the selected month were dispersed. What's more, the user can hover her mouse over
a day of the month to see the gross sales for that particular day.
Enhancing the User Experience With An UpdatePanel
Every time a user clicks one of the columns in the chart, a full page postback ensues. The browser re-requests the web page, sending the names and values of all of the form fields to the server. On the server, the page proceeds through its lifecycle and the entire HTML of the rendered page is returned to the browser, where it is displayed. This interaction is a bit unideal for a number of reasons, the key one being that only a small portion of the page is actually changed when clicking on a column, yet all of the page's markup is regenerated.
Ajax helps mitigate this problem by reducing the information exchanged between the browser and the server and by seamlessly integrating the updated content into the page without needing to redraw the entire screen. As discussed in my multi-part series, Building Interactive User Interfaces with Microsoft ASP.NET AJAX, implementing Ajax techniques in an ASP.NET website is relatively easy thanks to the ASP.NET Ajax Framework.
We can enhance our demo to use Ajax by adding an UpdatePanel to the page and putting the Calendar and legend inside of it. Next, we need to tell the UpdatePanel to "refresh"
itself whenever the user clicks one of the columns in the chart by adding an
AsyncPostBackTrigger to the UpdatePanel. The following declarative markup (which is
heavily abbreviated) shows the Chart, the UpdatePanel, the legend and the Calendar control. Note how the Chart is outside of the UpdatePanel - only the details that are displayed
when clicking a column in the chart are part of the UpdatePanel. Also take note of the
AsyncPostBackTrigger trigger in the UpdatePanel's declarative syntax. This
AsyncPostBackTrigger says simply, "Trigger a partial page postback whenever the Chart's
Click event fires."
That's all there is to it! With the addition of an UpdatePanel and an
AsyncPostBackTrigger, and by placing the Calendar and legend inside of the UpdatePanel,
we now have a chart that we can drill into and that uses Ajax techniques to improve the user experience.
Creating Real Time Charts
The charts we have examined throughout this article series have all displayed static data whose values are not changing. For example, the charts showing the number of products per category or the sales per category per year are pulling data from a database and that data is (relatively) fixed. It's not like new sales data for 1997 is being added every couple of seconds, or new products are being added an existing category every minute of the day.
But what if you need to chart data that is being updated in real time? Take Windows Task Manager, as an example. The Performance tab in Windows Task Manager shows CPU Usage History and Physical Memory Usage History as line charts being updated in real time. As each second (or so) passes, the chart is updated with the latest CPU and physical memory readings. In a business setting, you may be interested in tracking how many users are currently signed into your site, or the changing values for a particular stock quote.
Creating such real time charts in a web application is challenging and carries some concerns around performance and scalability because in order for the chart to be updated the browser must make a request back to the server to get an updated chart image. The good news is that with Ajax you can have just the chart image refreshed (as needed) rather than reloading the entire page. The download available at the end of this article includes a demo of a real time chart that uses Ajax techniques and the ASP.NET Ajax Framework's Timer control to refresh the chart every 1.5 seconds.
Specifically, the page contains a line chart inside of an UpdatePanel. The line chart's Y axis ranges from 0 to 100 and represents the reading from some fictional device or
sensor. The X axis is used to record the time of the reading. The UpdatePanel also includes a Timer control whose
Interval property is
set to 1500. Consequently, every 1,500 milliseconds (or 1.5 seconds) the Timer will "tick," which invokes a postback. Because the Timer control is inside of the UpdatePanel,
it actually causes a partial page postback instead of a full page postback.
One very important part of creating such a real time chart is to set the Chart's
EnableViewState property True. By default, this property is set to False, which
means that points added to a series'
Points collection are not remembered across postbacks. For a real time chart we need to have the Chart control
remember these values so that on each "tick" we can add the latest value without having to worry about re-adding the previous ones.
On the partial page postback, the Timer's
Tick event is fired and the
Tick event handler (if defined) will execute. The demo contains an event
handler for this
Tick event and in here we add a new point to the chart. The X value is the current time, the Y value is a randomly selected point that ranges
between 5 "values" less than the previous point to 5 "values" more. (I use the word "values" here because we don't have a unit of measurement for the Y axis. If we were reading
from a sensor that measured percentages, such as a CPU workload percentage, we would say that the randomly selected point ranges between 5 percentage points less to 5 percentage
points more than the previous reading.)
The following (abbreviated) code shows the logic used to add a random point to the chart when the Timer "ticks."
series is a reference to the Chart's only series, which is what contains the data points that are plotted on the chart. If there are no points in the
Points collection then an initial random point between 40 and 60 is added. Next, the previously-added points' Y value is determined and the next
point's Y value is computed by taking the previous value and adding to it a number between -5 and 5. Finally, this new point is added to the
As new points are added to the chart on every tick, we'll eventually run out of room on the right side of the chart. To remedy this we need to do two things:
- Keep only the 100 most recently-added points (or the 50 most recent or 200 most recent or whatever you decide on...) , and
- Adjust the X axis
Maximumvalues. This keeps the earliest added points to the far left of the axis and the just-added point on the far-right.
Titleis updated to show the time of the most recent reading.
The remainder of the
Tick event handler follows.
The following screen shot shows the real time chart in action. The first one shows the chart after having collected about 50 readings (so after 90 seconds, or so).
The second screen shot shows the real time chart several minutes later. Note how the data has filled the entire width of the X axis. As each new reading is made (that is,
at every 1.5 seconds) a new point is added to the right, the left-most point is removed, and the X axis's
Maximum values are updated