Recipe 15.3. Creating Bar Charts on the Fly


Problem

You want to create a bar chart on the fly without having to resort to a commercial package.

Solution

Use a combination of data binding with a Repeater control and the well-known HTML trick of stretching an image to create the bars.

In the .aspx file, add a Repeater control with an ItemTemplate.

In the code-behind class for the page, use the .NET language of your choice to:

  1. Assign the data source to the Repeater control and bind it.

  2. In the ItemDataBound event handler called for each item in the Repeater, set the width of the bar in the passed Repeater row.

Figure 15-2 shows some typical output. Examples 15-7, 15-8 through 15-9 show the .aspx file and VB and C# code-behind files for an application that implements this solution.

Discussion

This recipe provides a simple approach that combines data binding and HTML tricks to create a bar graph with little coding and without the need to purchase any additional components. By using more complex HTML, you can add more labels and other enhancements to this recipe, which may make it more useful for your situation.

Figure 15-2. Creating a bar chart output dynamically


The example we use to illustrate this solution generates a bar chart from chapter and problem data in a database. (The source of the data is not that important; the technique for generating the graph on the fly is the focus of this recipe.) The bar chart is created from an HTML table, with the top row used to label the chart.

This recipe advocates using a Repeater control to generate the rows in a table that represent the bars on the chart. The rows generated by the Repeater are defined in the ItemTemplate element, which in our example contains two columns. The first column is used to output the chapter number. In our example, the chapter number is obtained by binding the cell text to the Chapter column in the data source.

The second column contains the bar representing the number of problems in the chapter. The bar is created by using an HTML image tag with the source set to a one-pixel-by-one-pixel image. The height and width attributes of the image "stretch" the image to the size of the bar needed to represent the number of problems in the chapter. In our example, the height is set to a fixed value of 15 pixels, but the width is adjusted to represent the number of problems in the chapter. The width is adjusted in the code-behind and is discussed later.

The second column also contains a label to indicate the number of problems in the chapter. The number of problems in a chapter is obtained by binding the cell text to the ProblemCount column in the data source. This label is placed at the end of the bar with a non-breaking space ( ) to separate the label from the end of the bar.

The Page_Load method in the example code-behind reads the data from the database and then binds the data to the Repeater control on the page.

The code-behind class also implements the ItemDataBound event handler to provide the ability to adjust the width of the image used for the bar. The ItemDataBound event executes once per row in the Repeater as the row is data bound. In this event, we need to get a reference to the HTML image in the row using the FindControl method of the row and set the width of the image to reflect the number of problems in the chapter represented by the row.

If this recipe does not provide the richness you need for your chart, you can create an image using the concepts presented in Recipe 15.1. The System.Drawing classes provide all of the functionality to create sophisticated charts using the GDI+ Library. They do require more coding, however, as you must build your graphs from the ground up using the basic ingredients of pen, brush, point, rectangle, etc.

See Also

Recipe 15.1 and MSDN Help for more information on the System.Drawing class

Example 15-7. Creating a bar chart dynamically (.aspx)

 <%@ Page Language="VB" MasterPageFile="~/ASPNetCookbookVB.master" AutoEventWireup="false" CodeFile="CH15CreateChartVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH15CreateChartVB" Title="Create Chart" %> <asp:Content  runat="server" ContentPlaceHolder> <div align="center" > Dynamic Chart Creation (VB) </div> <table align="center" border="2" cellpadding="10"> <tr> <td> <table cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center" colspan="2" > Problems Per Chapter<br /><br /></td> </tr> <asp:Repeater  Runat="server" OnItemDataBound="repChartBar_ItemDataBound"> <ItemTemplate> <tr> <td > <%#Eval("Chapter")%>&nbsp; </td> <td > <img  runat="server" src="/books/1/505/1/html/2/images/blueSpacer.gif" border="0" height="15" align="middle" alt="bar"/> &nbsp;[<%#Eval("ProblemCount")%>] </td> </tr> </ItemTemplate> </asp:Repeater> </table> </td> </tr> </table> </asp:Content> 

Example 15-8. Create bar chart dynamically code-behind (.vb)

 Option Explicit On Option Strict On Imports System Imports System.Configuration.ConfigurationManager Imports System.Data Imports System.Data.Common Imports System.Data.OleDb Namespace ASPNetCookbook.VBExamples ''' <summary> ''' This class provides the code-behind for ''' CH15CreateChartVB.aspx ''' </summary> Partial Class CH15CreateChartVB Inherits System.Web.UI.Page '''*********************************************************************** ''' <summary> ''' This routine provides the event handler for the page load event. It ''' is responsible for initializing the controls on the page. ''' </summary> ''' ''' <param name="sender">Set to the sender of the event</param> ''' <param name="e">Set to the event arguments</param> Private Sub Page_Load(ByVal sender As Object, _   ByVal e As System.EventArgs) Handles Me.Load Dim dbConn As OleDbConnection = Nothing Dim dc As OleDbCommand Dim dr As OleDbDataReader Dim strConnection As String Dim strSQL As String If (Not Page.IsPostBack) Then Try 'get the connection string from web.config and open a connection 'to the database strConnection = _ ConnectionStrings("dbConnectionString").ConnectionString dbConn = New OleDb.OleDbConnection(strConnection) dbConn.Open( ) 'build the query string and get the data from the database strSQL = "SELECT DISTINCT ChapterID AS Chapter, " & _  "count(*) AS ProblemCount " & _  "FROM Problem " &_  "GROUP BY ChapterID" dc = New OleDbCommand(strSQL, dbConn) dr = dc.ExecuteReader( ) 'set the source of the data for the repeater control and bind it repChartBar.DataSource = dr repChartBar.DataBind( ) Finally 'clean up If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End If End Sub 'Page_Load '''*********************************************************************** ''' <summary> ''' This routine is the event handler that is called for each item in the ''' repeater after a data bind occurs. It is responsible for setting the ''' width of the bar in the passed repeater row to reflect the number of ''' problems in the chapter the row represents ''' </summary> ''' ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Protected Sub repChartBar_ItemDataBound(ByVal sender As Object, _ ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Dim img As System.Web.UI.HtmlControls.HtmlImage 'get a reference to the image used for the bar in the row img = CType(e.Item.FindControl("imgChartBar"), _ System.Web.UI.HtmlControls.HtmlImage) 'set the width to the number of problems in the chapter for this row 'multiplied by a constant to stretch the bar a bit more img.Width = _ CInt(CType(e.Item.DataItem, DbDataRecord)("ProblemCount")) * 10 End Sub 'repChartBar_ItemDataBound End Class 'CH15CreateChartVB End Namespace 

Example 15-9. Creating a bar chart dynamically code-behind (.cs)

 using System; using System.Configuration; using System.Data; using System.Data.Common; using System.Data.OleDb; namespace ASPNetCookbook.CSExamples { /// <summary> /// This class provides the code-behind for /// CH15CreateChartCS.aspx /// </summary> public partial class CH15CreateChartCS : System.Web.UI.Page { ///*********************************************************************** /// <summary> /// This routine provides the event handler for the page load event. /// It is responsible for initializing the controls on the page. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void Page_Load(object sender, EventArgs e) { OleDbConnection dbConn = null; OleDbCommand dc = null; OleDbDataReader dr = null; string strConnection = null; String strSQL = null; if (!Page.IsPostBack) { try { // get the connection string from web.config and open a connection // to the database strConnection = ConfigurationManager. ConnectionStrings["dbConnectionString"].ConnectionString; dbConn = new OleDbConnection(strConnection); dbConn.Open( ); // build the query string and get the data from the database strSQL = "SELECT DISTINCT ChapterID AS Chapter, " +  "count(*) AS ProblemCount " +  "FROM Problem " +  "GROUP BY ChapterID"; dc = new OleDbCommand(strSQL, dbConn); dr = dc.ExecuteReader( ); // set the source of the data for the repeater control and bind it repChartBar.DataSource = dr; repChartBar.DataBind( ); } finally { // clean up if (dbConn != null) { dbConn.Close( ); } } } } // Page_Load ///*********************************************************************** /// <summary> /// This routine is the event handler that is called for each item in the /// repeater after a data bind occurs. It is responsible for setting the /// width of the bar in the passed repeater row to reflect the number of /// problems in the chapter the row represents. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void repChartBar_ItemDataBound(Object sender,   System.Web.UI.WebControls.RepeaterItemEventArgs e) { System.Web.UI.HtmlControls.HtmlImage img = null; // get a reference to the image used for the bar in the row img = (System.Web.UI.HtmlControls.HtmlImage)   (e.Item.FindControl("imgChartBar")); // set the width to the number of problems in the chapter for this row // multiplied by a constant to stretch the bar a bit more img.Width = (int)(((DbDataRecord)(e.Item.DataItem))["ProblemCount"]) * 10; } // repChartBar_ItemDataBound } // CH15CreateChartCS } 



ASP. NET Cookbook
ASP.Net 2.0 Cookbook (Cookbooks (OReilly))
ISBN: 0596100647
EAN: 2147483647
Year: 2003
Pages: 202

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net