Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating Dynamic Graphs in ASP.NET using GDI+

0.00/5 (No votes)
10 Jul 2004 1  
A Web Control to Create Dynamic Graphs in ASP.NET using GDI+

Introduction

This article explains how we can use GDI+ to create on the fly graphs in ASP.NET. The code in the 'Source Code' section is the code for the web control which can be used to add graphs in your ASP.NET application which refreshes itself automatically after every specified duration.

Using the Web Control

To use this web control add a reference of the rGraph.dll file (Click 'Download Demo Project' and extract the dll) in your ASP.NET application. In your code set the Width and Height of the Graph. Set TmpGraphFiles to some valid location on the server. Next set the DataSource property to a valid DataSource. The data source should contain first column as SubTexts (string) and subsequent columns should be numeric (or floating point). If only one numeric column is specified only 1 bar will be shown per SubText. If more numeric columns are present then they'll be grouped. Finally call the Draw function. If you want the graph to be refreshed automatically set the AutoRefresh property to true. Also set the duration for the same.

About GDI+

GDI+ is a graphics device interface that allows programmers to write device-independent applications. The services of GDI+ are exposed through a set of managed classes. GDI+ is the successor to GDI, the graphics device interface included with earlier versions of Windows. GDI+ is an application programming interface (API) that is exposed through a set of classes deployed as managed code. This set of classes is called the managed class interface to GDI+.

A graphics device interface, such as GDI+, allows application programmers to display information on a screen or printer without having to be concerned about the details of a particular display device. The application programmer makes calls to methods provided by GDI+ classes and those methods in turn make the appropriate calls to specific device drivers. GDI+ insulates the application from the graphics hardware, and it is this insulation that allows developers to create device-independent applications.

Drawback of this user control

Problem :

GDI+ finally outputs a bitmap which i've saved as jpeg and used in a Image Web Contol. This creates unnecessary files on the server which should be cleaned up. The cleaning up stuff has not yet done by me. Multiple files are created as there can be multiple users and so to avoid the possibility of files getting overwritten and users receiving wrong information i'm generating unique files for every user.

Solution :

I've created a control which can display in-memory bitmaps. I'll upload the same soon. This way we need not save the file onto the server.

Improvements

The thing i'm trying now is to display graphs in 3D for MDX recordsets. I'm almost complete with it. It's a li'l buggy but 'll clean it up. And i'm trying to document it fully (BlueBubu, Colin Angus Mackay, Ray Cassick, eggie5, Chris Meech and leppie.... are u listening ??). Please improve the code if u do get it (coz comments are totally absent. Sorry !!!). The code is all yours.

Source Code

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Drawing.Imaging;
using System.Data;
using System.Data.SqlTypes;
using System.IO;
using System.ComponentModel;
using System.Text;

namespace GraphsLibrary
{
    /// <summary>

    /// Summary description for Class1.

    /// </summary>


public class Graph : WebControl
{
    protected int picWidth = 500;
    protected int picHeight = 200;
    protected int panelWidth = 0;
    protected float barHSpacing = 4;
    protected float vScale;
    protected int hScale;
    protected float maxActualHeight;
    protected float maxActualWidth;
    protected int maxBarAllowedWidth = -1;
    protected int footerHeight=50;
    protected string tempPath=@"C:\";
        protected DataSet ds;
    protected int graphType=1;
    protected int refreshPeriod=2500;
    protected bool autoRefresh = true;
    private string _imageURL;


    [Category("Data")] 
    public DataSet DataSource
    {
        get
        {
            return ds;
        }
        set
        {
            ds = value;
        }
    }

    [Category("Behavior")] 
    public int RefreshPeriod
    {
        get
        {
            return refreshPeriod;
        }
        set
        {
            refreshPeriod = value;
        }
    }

    [Category("Behavior")] 
    public bool AutoRefresh
    {
        get
        {
            return autoRefresh;
        }
        set
        {
            autoRefresh = value;
        }
    }

    [Category("Layout")] 
    public int RightPanelWidth
    {
        get
        {
            return panelWidth;
        }
        set
        {
            panelWidth = value;
        }
    }

    [Category("Layout")] 
    public float SpacingBetweenBars
    {
        get
        {
            return barHSpacing;
        }
        set
        {
            barHSpacing = value;
        }
    }


    [Category("Layout")] 
    public int MaxBarWidth
    {
        get
        {
            return maxBarAllowedWidth;
        }
        set
        {
            maxBarAllowedWidth = value;
        }
    }

    [Category("Data")] 
    public string TempGraphFilesPath
    {
        get
        {
            return tempPath;
        }
        set
        {
            tempPath = value;
        }
    }


    [Category("Layout")] 
    public int FooterHeight
    {
        get
        {
            return footerHeight;
        }
        set
        {
            footerHeight = value;
        }
    }

    [Category("Layout")] 
    public int Type
    {
        get
        {
            return graphType;
        }
        set
        {
            graphType = value;
        }
    }


    protected int[] clrArray = { Color.Blue.ToArgb(),
        Color.DarkBlue.ToArgb(),
        Color.DarkGreen.ToArgb(),
        Color.DarkRed.ToArgb(),
        Color.DeepPink.ToArgb(),
        Color.Coral.ToArgb(),
        Color.DarkSlateBlue.ToArgb(),
        Color.Goldenrod.ToArgb(),
        Color.Teal.ToArgb()
    };


    protected System.Drawing.Color clrBackground = 
             System.Drawing.Color.LightSteelBlue;

    public void Draw()
    {
        if(ds==null) throw new Exception(
        "No DataSource defined\nFirst Row : Names\nSecond Row : Values") ;
        int numGraphPoints = 0;
        int barWidth;
        Graphics objGraphics;
        DataTable dtblProducts = ds.Tables[0];
        int numbarsingrp = ds.Tables[0].Columns.Count-1;
        foreach(DataRow drowRow in dtblProducts.Rows)
        {
            for(int colno=1; colno < ds.Tables[0].Columns.Count;colno++)
                if(System.Single.Parse(drowRow[colno].ToString())
                     > maxActualHeight)
                    maxActualHeight = System.Single.Parse(
                     drowRow[colno].ToString());
            numGraphPoints++;
        }
        vScale = picHeight/maxActualHeight;
        if(barHSpacing==-1)
        {
            barWidth=(int)(picWidth/(numGraphPoints + 
                      ((float)numGraphPoints-1)*20/100));
            barHSpacing = barWidth * 20/100;
        }
        else
            barWidth=(picWidth - (int)barHSpacing * 
                 (numGraphPoints - 1))/numGraphPoints;

        Bitmap objBitmap = new Bitmap(picWidth+panelWidth, 
                picHeight+footerHeight);
        objGraphics = Graphics.FromImage(objBitmap);
        objGraphics.Clear(clrBackground);
        DataRow drowRow1;
        int allowedWidth = barWidth;
        int offset = 0;
        if(graphType==1 || graphType==3)
        {
            //barWidth = barWidth/numbarsingrp;

            for(int i = 0; i < numGraphPoints; i++)
            {
                if (maxBarAllowedWidth < barWidth && 
                   maxBarAllowedWidth != -1) 
                {
                    offset = (barWidth - maxBarAllowedWidth)/2;
                    allowedWidth = maxBarAllowedWidth;
                }
                drowRow1 = dtblProducts.Rows[i];
                for(int k =1;k<=numbarsingrp;k++)
                {
                    objGraphics.FillRectangle(new SolidBrush(Color.FromArgb
                        (clrArray[(k )%clrArray.Length])),offset + 
                        (i*(barWidth + barHSpacing)) + ((k-1) * 
                        barWidth/numbarsingrp),picHeight - 
                        System.Single.Parse(drowRow1[k].ToString())*vScale,
                        allowedWidth/numbarsingrp ,
                        System.Single.Parse(drowRow1[k].ToString())*vScale);
                }

                RectangleF rf = new RectangleF();
                rf.X=offset + i * (barWidth + barHSpacing);
                rf.Y=picHeight;
                rf.Height=footerHeight;
                rf.Width=barWidth+barHSpacing;
                StringFormat sf= new StringFormat();

                sf.FormatFlags = StringFormatFlags.DirectionVertical;
                Font fnt = new Font(this.Font.Name, 10);
                objGraphics.DrawString(drowRow1[0].ToString(), 
                    fnt, new SolidBrush(Color.Black),rf,sf);
            }
        }
        if(graphType==0 || graphType==3)
        {
            float oldX=0;
            float oldY=picHeight;
            for(int i = 0; i < numGraphPoints; i++)
            {
                if (maxBarAllowedWidth < barWidth && 
                  maxBarAllowedWidth != -1) 
                {
                    offset = (barWidth - maxBarAllowedWidth)/2;
                    allowedWidth = maxBarAllowedWidth;
                }
                drowRow1 = dtblProducts.Rows[i];
                objGraphics.FillRectangle(new SolidBrush(Color.White),
                    offset + i * (barWidth + barHSpacing)+ 
                    (barWidth + barHSpacing)/2 - 2,picHeight - 
                    System.Single.Parse(drowRow1[1].ToString())*
                    vScale-2, 4,4);
                objGraphics.DrawLine(Pens.White,oldX,oldY,offset + 
                    i * (barWidth + barHSpacing)+ 
                    (barWidth + barHSpacing)/2,picHeight - 
                    System.Single.Parse(drowRow1[1].ToString())*vScale);
                oldX=offset + i * (barWidth + barHSpacing) + 
                    (barWidth + barHSpacing)/2;
                oldY=picHeight - System.Single.Parse(
                   drowRow1[1].ToString())*vScale;
                RectangleF rf = new RectangleF();
                rf.X=offset + i * (barWidth + barHSpacing);
                rf.Y=picHeight;
                rf.Height=footerHeight;
                rf.Width=barWidth+barHSpacing;
                StringFormat sf= new StringFormat();

                sf.FormatFlags = StringFormatFlags.DirectionVertical;
                Font fnt = new Font(this.Font.Name, 10);
                objGraphics.DrawString(drowRow1[0].ToString(), fnt, 
                    new SolidBrush(Color.Black),rf,sf);
            }
        }

        objGraphics.DrawLine(new Pen(Color.Black,1),
               0,picHeight,picWidth,picHeight);

        int j = 0;
        while(File.Exists(tempPath + @"graph" + j.ToString() + ".jpg")==true)
            j++;
        _imageURL = tempPath + @"graph" + j.ToString() + ".jpg";
        objBitmap.Save(_imageURL, ImageFormat.Jpeg);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        System.Web.UI.WebControls.Image imgGraph=
              new System.Web.UI.WebControls.Image();
        picWidth = (int)(this.Width.Value-panelWidth);
        picHeight = (int)(this.Height.Value-footerHeight);
        //DrawBarGraph();

        Draw();

        if(autoRefresh==true)
        {
            imgGraph.Width=picWidth+panelWidth; 
            imgGraph.Height=picHeight+footerHeight;
            imgGraph.ImageUrl=_imageURL;
            imgGraph.RenderControl(writer);
            StringBuilder sb = new StringBuilder();
            sb.Append(
"\n<script language="\""javascript\"> \n <!-- \n setTimeout( \"");
            sb.Append(base.Page.GetPostBackEventReference(this));
            sb.Append("\", ");
            sb.Append(refreshPeriod.ToString());
            sb.Append("); \n // --> \n </script>");
            writer.Write(sb.ToString()); 
        }
        base.Render (writer);
    }
 }
}

Credits

Thanx BlueBubu, Colin Angus Mackay, Ray Cassick, eggie5, Chris Meech and leppie for flaming me for my first version. Suggestions (and even flames) from you guys are most welcome.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here