Click to See Complete Forum and Search --> : Dynamic piechart graphic creation (using ASP.NET)


CardboardHammer
11-25-2003, 02:34 PM
The files below can be used to create piechart graphics on the fly. This is copied from production code. Feel free to use or modify (it does everything I need it to do and then some, if it doesn't do everything you need, don't complain), but don't post this code elsewhere and claim it as your own.

PieChart.aspx.vb
Imports System.Drawing
Imports System.Drawing.Imaging

Public Class PieChart
Inherits System.Web.UI.Page

#Region " Web Form Designer Generated Code "

'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

End Sub

Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub

#End Region

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Output error image on bad data... everything else, revert to defaults on error
Dim arrValues As Array
Dim arrVals() As Single
Dim sSum As Single
Dim arrColors() As Color
Dim numColors As Int32

Dim strFormat As String
Dim lSize As Int32
Dim sCurrentDegree As Single
Dim iLoop As Int32
Dim iEndLoop As Int32
Dim objBkgrColor As Color
objBkgrColor = Color.White 'Default

Dim coll As Collections.Specialized.NameValueCollection
coll = Request.QueryString

arrValues = coll.GetValues("f")
If Not arrValues Is Nothing Then
Try
strFormat = Convert.ToString(arrValues.GetValue(0))
Catch 'Ignore any error
End Try
End If

arrValues = coll.GetValues("s")
If Not arrValues Is Nothing Then
Try
lSize = Convert.ToInt32(arrValues.GetValue(0))
If lSize <= 0 Then
'Default size
lSize = 200
ElseIf lSize > 800 Then
'Maximum size
lSize = 800
End If
Catch 'Use Default size
lSize = 200
End Try
Else
'Use Default size
lSize = 200
End If

arrValues = coll.GetValues("a")
If Not arrValues Is Nothing Then
Try
sCurrentDegree = Convert.ToSingle(arrValues.GetValue(0))
Catch 'Ignore any error
End Try
End If

arrValues = coll.GetValues("c")
If Not arrValues Is Nothing Then
iEndLoop = arrValues.GetUpperBound(0)
Try
Dim arrTempColors(iEndLoop) As Color

For iLoop = 0 To iEndLoop
arrTempColors(iLoop) = Color.FromArgb(Convert.ToInt32(arrValues.GetValue(iLoop)))
Next
arrColors = arrTempColors
Catch 'IRevert to default colors on error
'Get default colors
Procedures.GetDefaultColors(arrColors)
End Try
Else
'Get default colors
Procedures.GetDefaultColors(arrColors)
End If

numColors = arrColors.GetLength(0)

arrValues = coll.GetValues("b")
If Not arrValues Is Nothing Then
Try
objBkgrColor = Color.FromArgb(Convert.ToInt32(arrValues.GetValue(0)))
Catch 'Ignore any error
End Try
End If

Dim sTemp As Single
arrValues = coll.GetValues("d")
If Not arrValues Is Nothing Then
Try
iEndLoop = arrValues.GetUpperBound(0)
Dim arrValsTemp(iEndLoop) As Single
For iLoop = 0 To iEndLoop
sTemp = Convert.ToSingle(arrValues.GetValue(iLoop))
If sTemp < 0 Then
iEndLoop = -1
End If
arrValsTemp(iLoop) = sTemp
sSum += arrValsTemp(iLoop)
Next
arrVals = arrValsTemp
Catch 'ignore all errors...?
iEndLoop = -1
End Try
Else
iEndLoop = -1
End If

arrValues = coll.GetValues("r")
If Not arrValues Is Nothing Then
Try
If Convert.ToString(arrValues.GetValue(0)) = "-" Then
sSum *= -1 'counterclockwise rotation
End If
Catch 'Ignore any error
End Try
End If

' Create a Bitmap instance and a Graphics instance
Dim objBitmap As Bitmap
objBitmap = New Bitmap(lSize, lSize, PixelFormat.Format32bppArgb)
Dim objGraphics As Graphics
objGraphics = Graphics.FromImage(objBitmap)

'Put a white background in
objGraphics.FillRectangle(New SolidBrush(objBkgrColor), 0, 0, lSize, lSize)

For iLoop = 0 To iEndLoop
'use twice, calculate once
sTemp = 360 * arrVals(iLoop) / sSum
'Draw the slice
objGraphics.FillPie(New SolidBrush(arrColors(iLoop Mod numColors)), 0, 0, lSize, lSize, sCurrentDegree, sTemp)
' increment the currentDegree
sCurrentDegree += sTemp
Next

' Save the image to the OutputStream
If strFormat = "jpeg" Then
Response.ContentType = "image/jpeg"
objBitmap.Save(Response.OutputStream, ImageFormat.Jpeg)
Else
Response.ContentType = "image/gif"
objBitmap.Save(Response.OutputStream, ImageFormat.Gif)
End If

' clean up...
objGraphics.Dispose()
objBitmap.Dispose()
End Sub

End Class


PieChart.aspx
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="PieChart.aspx.vb" Inherits="TEST_NET.PieChart" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head><LINK REL=stylesheet HREF="main.css">
<title>PieChart</title>
<meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">
<meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
<meta name=vs_defaultClientScript content="JavaScript">
<meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body MS_POSITIONING="GridLayout">

<form id="Form1" method="post" runat="server">

</form>

</body>
</html>


Procedures.vb
Option Explicit On
Option Strict On

Imports System.Data.SqlClient
Imports System.Drawing
Imports System.Drawing.Imaging

Public Module Procedures
Public Sub GetDefaultColors(ByRef colors() As Color)
Dim colors1(20) As Color
colors = colors1
colors(0) = Color.FromArgb(&HFF000000)
colors(1) = Color.FromArgb(&HFFFF6633)
colors(2) = Color.FromArgb(&HFF9900CC)
colors(3) = Color.FromArgb(&HFF99CCCC)
colors(4) = Color.FromArgb(&HFF006600)
colors(5) = Color.FromArgb(&HFFFFCC66)
colors(6) = Color.FromArgb(&HFF666633)
colors(7) = Color.FromArgb(&HFFCC0099)
colors(8) = Color.FromArgb(&HFF009999)
colors(9) = Color.FromArgb(&HFFCCCC33)
colors(10) = Color.FromArgb(&HFFCC3300)
colors(11) = Color.FromArgb(&HFF66CCFF)
colors(12) = Color.FromArgb(&HFF330099)
colors(13) = Color.FromArgb(&HFFCC3399)
colors(14) = Color.FromArgb(&HFFCC9900)
colors(15) = Color.FromArgb(&HFFCC6699)
colors(16) = Color.FromArgb(&HFF006699)
colors(17) = Color.FromArgb(&HFF9900CC)
colors(18) = Color.FromArgb(&HFFFFFF00)
colors(19) = Color.FromArgb(&HFFCCCC00)
End Sub
End Module

PeOfEo
12-06-2003, 11:14 AM
sweet. I do not go into this forum much but I am working on a bar chart right now for a poll I am making. :D

CardboardHammer
12-10-2003, 01:45 PM
I need to do a lot more with this to get it to do what I want (and I've been ignoring it for quite a while), but this might be of some help to you.

BarChart.aspx.vb

Imports System.Drawing
Imports System.Drawing.Imaging

Public Class BarChart
Inherits OtherPage

#Region " Web Form Designer Generated Code "

'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

End Sub

Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub

#End Region

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Output error image on bad data... everything else, revert to defaults on error
Dim arrValues As Array
Dim arrVals() As Single
Dim sSum As Single
Dim arrColors() As Color
Dim numColors As Int32
Dim bHorizontal As Boolean
Dim bDescending As Boolean
Dim strFormat As String
Dim lSizeX As Int32
Dim lSizeY As Int32
Dim sCurrent
Dim iLoop As Int32
Dim iEndLoop As Int32
Dim objBkgrColor As Color
objBkgrColor = Color.White 'Default

Dim coll As Collections.Specialized.NameValueCollection
coll = Request.QueryString

arrValues = coll.GetValues("f")
If Not arrValues Is Nothing Then
Try
strFormat = Convert.ToString(arrValues.GetValue(0))
Catch 'Ignore any error
End Try
End If

arrValues = coll.GetValues("h")
If Not arrValues Is Nothing Then
Try
lSizeY = Convert.ToInt32(arrValues.GetValue(0))
If lSizeY <= 0 Then
'Default size
lSizeY = 200
ElseIf lSizeY > 800 Then
'Maximum size
lSizeY = 800
End If
Catch 'Use Default size
lSizeY = 200
End Try
Else
'Use Default size
lSizeY = 200
End If

arrValues = coll.GetValues("w")
If Not arrValues Is Nothing Then
Try
lSizeX = Convert.ToInt32(arrValues.GetValue(0))
If lSizeX <= 0 Then
'Default size
lSizeX = 200
ElseIf lSizeX > 800 Then
'Maximum size
lSizeX = 800
End If
Catch 'Use Default size
lSizeX = 200
End Try
Else
'Use Default size
lSizeX = 200
End If

arrValues = coll.GetValues("l")
If Not arrValues Is Nothing Then
Try
If Convert.ToString(arrValues.GetValue(0)) = "h" Then
bHorizontal = True
End If
Catch 'Ignore any error
End Try
End If

arrValues = coll.GetValues("o")
If Not arrValues Is Nothing Then
Try
If Convert.ToString(arrValues.GetValue(0)) = "d" Then
bDescending = True
End If
Catch 'Ignore any error
End Try
End If

arrValues = coll.GetValues("c")
If Not arrValues Is Nothing Then
iEndLoop = arrValues.GetUpperBound(0)
Try
Dim arrTempColors(iEndLoop) As Color

For iLoop = 0 To iEndLoop
arrTempColors(iLoop) = Color.FromArgb(Convert.ToInt32(arrValues.GetValue(iLoop)))
Next
arrColors = arrTempColors
Catch 'IRevert to default colors on error
'Get default colors
Procedures.GetDefaultColors(arrColors)
End Try
Else
'Get default colors
Procedures.GetDefaultColors(arrColors)
End If

numColors = arrColors.GetLength(0)

arrValues = coll.GetValues("b")
If Not arrValues Is Nothing Then
Try
objBkgrColor = Color.FromArgb(Convert.ToInt32(arrValues.GetValue(0)))
Catch 'Ignore any error
End Try
End If

Dim sTemp As Single
arrValues = coll.GetValues("d")
If Not arrValues Is Nothing Then
Try
iEndLoop = arrValues.GetUpperBound(0)
Dim arrValsTemp(iEndLoop) As Single
For iLoop = 0 To iEndLoop
sTemp = Convert.ToSingle(arrValues.GetValue(iLoop))
If sTemp < 0 Then
iEndLoop = -1
End If
arrValsTemp(iLoop) = sTemp
sSum += arrValsTemp(iLoop)
Next
arrVals = arrValsTemp
Catch 'ignore all errors...?
iEndLoop = -1
End Try
Else
iEndLoop = -1
End If


' Create a Bitmap instance and a Graphics instance
Dim objBitmap As Bitmap
objBitmap = New Bitmap(lSizeX, lSizeY, PixelFormat.Format32bppArgb)
Dim objGraphics As Graphics
objGraphics = Graphics.FromImage(objBitmap)

'Put a background in
objGraphics.FillRectangle(New SolidBrush(objBkgrColor), 0, 0, lSizeX, lSizeY)

If sSum > 0 Then
If bHorizontal Then
If bDescending Then
For iLoop = 0 To iEndLoop
'use twice, calculate once
sTemp = lSizeX * arrVals(iLoop) / sSum
'Draw the slice
objGraphics.FillRectangle(New SolidBrush(arrColors(iLoop Mod numColors)), sCurrent, 0, sTemp, lSizeY)
' increment the currentX
sCurrent += sTemp
Next
Else
sCurrent = lSizeX
For iLoop = 0 To iEndLoop
'use twice, calculate once
sTemp = lSizeX * arrVals(iLoop) / sSum
' increment the currentX
sCurrent += (sTemp * -1)
'Draw the slice
objGraphics.FillRectangle(New SolidBrush(arrColors(iLoop Mod numColors)), sCurrent, 0, sTemp, lSizeY)
Next
End If
Else
If bDescending Then
For iLoop = 0 To iEndLoop
'use twice, calculate once
sTemp = lSizeY * arrVals(iLoop) / sSum
'Draw the slice
objGraphics.FillRectangle(New SolidBrush(arrColors(iLoop Mod numColors)), 0, sCurrent, lSizeX, sTemp)
' increment the currentY
sCurrent += sTemp
Next
Else
sCurrent = lSizeY
For iLoop = 0 To iEndLoop
'use twice, calculate once
sTemp = lSizeY * arrVals(iLoop) / sSum
' increment the currentY
sCurrent += (sTemp * -1)
'Draw the slice
objGraphics.FillRectangle(New SolidBrush(arrColors(iLoop Mod numColors)), 0, sCurrent, lSizeX, sTemp)
Next
End If
End If
End If

' Save the image to the OutputStream
If strFormat = "jpeg" Then
Response.ContentType = "image/jpeg"
objBitmap.Save(Response.OutputStream, ImageFormat.Jpeg)
Else
Response.ContentType = "image/gif"
objBitmap.Save(Response.OutputStream, ImageFormat.Gif)
End If

' clean up...
objGraphics.Dispose()
objBitmap.Dispose()
End Sub

End Class


EDIT for misspelling of "code" in end tag.

PeOfEo
12-20-2003, 04:33 PM
drawing is hard! It takes a real butt load of code to make dynamic images. I have not done anything with the poll I was making yet, but one day when I have lots of free time I guess I will play around with it. It is on the lower end of my priorities. I want to redo my forum and my layout first. I need to basically completly redo them both so itl take a lil while.

zachzach
12-24-2003, 12:29 PM
for the poll you said you were making, using just javascript, a table and an image would work

just make javascript determine how many votes there were, what the percentage of yes/nos or whatever there were and write a table with an image and the hieght of that image is that percentage.Or you could do the same thing with plain old asp even easier

PeOfEo
12-24-2003, 12:34 PM
Well, yes i know. Just take the votes and then do a little math to detirmine % widths for a span or div. But When you acually create the image it looks nicer in my opinion, you can add things in like grid lines, gradiants etc, without having to worrie about browser compadability.

CardboardHammer
12-26-2003, 08:30 PM
Originally posted by PeOfEo
drawing is hard! It takes a real butt load of code to make dynamic images. ...

Actually, the drawing is easy. It's handling all the parameters from the URL that's bloating the code; and a big problem with IE is that you're limited to a certain total URL length... which inspires an idea: instead of creating an image based on the URL parameters (which are determined on the server side and put into the image link),
-do a db lookup on the parameters
-if no record is found then
---create the image on the server
---assign a unique filename to the image
---save the image in a web accessible directory on the server
---store the parameters, creation date and unique name in the db
-else
--get the unique filename from the record
--update field(s) that track(s) usage
-use the filename in the link.

The db and the image directory would need to be monitored to ensure that a reasonable amount of space is being used. Cleaning can be biased in favor of retaining frequently and recently used images.

The strategy above (and variants) wouldn't be appropriate in ALL circumstances, but it's not that hard to devise scenarios in which it would be very useful (images too complex to pack all the parameters at the end of the URL, frequent use of certain images that would otherwise be recreated everytime they fell out of the ASP.NET cache, etc.)... Maybe I'll do an implementation for personal amusement...