创建动态折线图






1.05/5 (16投票s)
2006年5月25日
19分钟阅读

101219
创建动态折线图
引言
从数据库数据创建折线图
本文介绍了如何使用VB.NET为Web窗体创建折线图。我认为市面上已经有许多用于创建折线图和图表的第三方组件。它们不会让你了解其内部工作原理。因此,我使用VB.NET中的GDI+创建了一个折线图。此外,你还将能够快速创建折线图。
使用代码
以下是用于创建折线图的函数代码
既然您已经知道如何从ASP.NET网页创建简单的图像,您就可以创建更复杂(且有用)的图像。在本文的其余部分,我将探讨如何使用.NET Framework的绘图类从数据库信息创建折线图。我将把所有这些功能构建到ASP.NET网页的一组函数中,这些函数最终会将动态创建的折线图的二进制内容流式传输到Response对象的OutputStream中。
虽然创建一组页面级函数来显示折线图可以完成当前任务,但一个更具可重用性的解决方案是将此功能封装到自定义定义的ASP.NET Web控件或已编译的自定义控件中。然而,这种方法的一个缺点是,自定义定义的ASP.NET Web控件或已编译的自定义控件必须将图像文件保存到Web服务器的文件系统中,然后从适当的img标签中进行渲染。虽然这并不难实现,但您必须处理我之前提到的缺点,包括每次生成图表时都会向Web服务器文件系统上的图像列表添加新图像这一事实。
1)为它创建一个另一个vb类文件,该文件将根据用户会话创建折线图 :===
类文件的代码已经完成,现在我们需要创建一个实例
此文件在需要折线图的Web窗体中,并设置适当的属性。
这里我以得分对比报告为例(日期 vs. 离职率和缺勤率)
此类文件 将根据您从数据库中提取的数据值生成折线图。
使用折线图绘制折线图以比较两支球队的得分。
折线图vb类文件名(如(LineChartAbs.vb)代码
‘导入这些命名空间
Imports System.Data
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Imports System.Web.UI
Public Class LineChartAbs
Public b As Bitmap
Public Title As String = "默认标题"
Public chartValues As ArrayList = New ArrayList
Public Xorigin As Single = 0
Public Yorigin As Single = 0
Public ScaleX As Single
Public ScaleY As Single
Public Xdivs As Single = 2
Public Ydivs As Single = 2
Private Width As Integer
Private Height As Integer
Private g As Graphics
Private p As Page
Private btn As Button
Structure datapoint
Public x As Single
Public y As Single
Public xCaption As String
Public yCaption As String
Public ATTRAVERAGE As String
Public valid As Boolean
End Structure
Public Sub New(ByVal myWidth As Integer, ByVal myHeight As Integer, ByVal myPage As Page)
Width = myWidth
Height = myHeight
ScaleX = myWidth
ScaleY = myHeight
b = New Bitmap(myWidth, myHeight)
g = Graphics.FromImage(b)
p = myPage
End Sub
Public Sub AddValue(ByVal x As Integer, ByVal y As Double, ByVal xCaption As String, ByVal yCaption As String)
Dim myPoint As datapoint
myPoint.x = x
myPoint.y = y
myPoint.xCaption = xCaption
myPoint.yCaption = yCaption
'myPoint.ATTRAVERAGE = ATTRAVERAGE
myPoint.valid = True
chartValues.Add(myPoint)
End Sub
Public Sub AddValueN(ByVal x As Integer, ByVal y As Double, ByVal xCaption As String, ByVal ATTRAVERAGE As String)
Dim myPoint As datapoint
myPoint.x = x
myPoint.y = y
myPoint.xCaption = xCaption
'myPoint.yCaption = yCaption
myPoint.ATTRAVERAGE = ATTRAVERAGE
myPoint.valid = True
chartValues.Add(myPoint)
End Sub
Public Sub AddValue(ByVal x As Integer, ByVal y As Double)
AddValue(x, y, x.ToString, y.ToString())
End Sub
Public Sub DisplayValues()
Dim i As Integer
Dim Labelvalue As String
Dim blackBrushN As Brush = New SolidBrush(Color.Black)
Dim axesFontN As Font = New Font("arial", 10)
Dim ChartInset As Integer = 500
Dim ChartWidth As Integer = Width - (2 * ChartInset)
Dim ChartHeight As Integer = Height - (2 * ChartInset)
For i = 0 To chartValues.Count
If i >= chartValues.Count Then
Labelvalue = ""
Else
Labelvalue = CType(chartValues(i), datapoint).xCaption
Labelvalue = Labelvalue & "-" & CType(chartValues(i), datapoint).yCaption
g.DrawString(Labelvalue, axesFontN, blackBrushN, Width + 1, Height)
End If
下一篇
End Sub
'Public Sub Draw(ByVal filename As String)
Public Sub Draw()
Dim i As Integer
Dim x As Single
Dim y As Single
Dim y1, y2 As Single
Dim x0 As Single
Dim y0 As Single
Dim PrintAonDot As Integer
Dim myLabel As String
Dim d1 As String
Dim m1, m2, m3 As String
Dim blackPen As Pen = New Pen(Color.Black, 1)
Dim RedPen As Pen = New Pen(Color.FromArgb(186, 5, 5), 1)
Dim bluePen As Pen = New Pen(Color.Blue, 1)
Dim blueBrush As Brush = New SolidBrush(Color.Blue)
Dim RedBrush As Brush = New SolidBrush(Color.FromArgb(109, 44, 0))
Dim MarunBrush As Brush = New SolidBrush(Color.FromArgb(109, 44, 0))
Dim blackBrush As Brush = New SolidBrush(Color.Black)
Dim axesFont As Font = New Font("verdana", 8, FontStyle.Bold)
p.Response.ContentType = "image/jpeg"
'g.FillRectangle(New SolidBrush(Color.LightYellow), 0, 0, Width, Height)
g.FillRectangle(New SolidBrush(Color.FromArgb(255, 216, 189)), 0, 0, Width, Height)
'Dim ChartInset As Integer = 50 旧测试更改
Dim ChartInset As Integer = 50
Dim ChartWidth As Integer = Width - (2 * ChartInset)
Dim ChartHeight As Integer = Height - (2 * ChartInset)
g.DrawRectangle(New Pen(Color.Blue, 1), ChartInset, ChartInset, ChartWidth, ChartHeight)
btn = New Button
btn.ID = "btnBack"
btn.Text = "deepchand"
g.DrawString(Title, New Font("verdana", 8, FontStyle.Bold), blueBrush, Width / 6, 5)
i = 0
i = 0
While i <= Xdivs
x = ChartInset + (i * ChartWidth) / Xdivs
y = ChartHeight + ChartInset
'myLabel = (Xorigin + (ScaleX * i / Xdivs)).ToString
' 此代码用于在格式中打印X轴值
If i >= chartValues.Count Then
'If i > chartValues.Count Then
myLabel = "天数->" & vbCrLf & " "
g.DrawString(myLabel, axesFont, blueBrush, x - 15, y + 10)
Else
'myLabel = CType(chartValues(i - 1), datapoint).xCaption 更改
myLabel = CType(chartValues(i), datapoint).xCaption
d1 = myLabel.Substring(0, 2).ToString
m1 = myLabel.Substring(3, 3).ToString
myLabel = d1 & vbCrLf & m1
g.DrawString(myLabel, axesFont, blackBrush, x - 10, y + 10)
End If
'g.DrawString(myLabel, axesFont, blackBrush, x - 8, y + 10)
g.DrawLine(blackPen, x, y + 2, x, y - 2)
If i < chartValues.Count Then
'' 在点上打印缺勤百分比
myLabel = CType(chartValues(i), datapoint).yCaption
x = (ChartWidth * (CType(chartValues(i), datapoint).x - Xorigin) / ScaleX) + ChartInset
y = ChartHeight - (ChartHeight * (CType(chartValues(i), datapoint).y - Yorigin) / ScaleY) + ChartInset - 15
g.DrawString(myLabel, axesFont, blackBrush, x - 10, y - 5)
''End 在点上打印缺勤百分比
End If
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
i = 0
i = 0
While i <= Ydivs
x = ChartInset
y = ChartHeight + ChartInset - (i * ChartHeight / Ydivs)
myLabel = (Yorigin + (ScaleY * i / Ydivs)).ToString & "%"
If i = Ydivs Then
Dim s1 As StringFormat = New StringFormat(StringFormatFlags.DirectionVertical)
myLabel = "<-缺勤"
g.DrawString(myLabel, axesFont, blueBrush, 15, y - 45, s1)
ElseIf (i Mod 5) = 0 Then
g.DrawString(myLabel, axesFont, blackBrush, 20, y - 6)
Else
myLabel = ""
g.DrawString(myLabel, axesFont, blackBrush, 20, y - 6)
End If
g.DrawLine(blackPen, x + 2, y, x - 2, y)
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
g.RotateTransform(180)
g.TranslateTransform(0, -Height)
g.TranslateTransform(-ChartInset, ChartInset)
g.ScaleTransform(-1, 1)
Dim prevPoint As datapoint = New datapoint
prevPoint.valid = False
i = 0
For Each myPoint As datapoint In chartValues
If prevPoint.valid = True Then
x0 = ChartWidth * (prevPoint.x - Xorigin) / ScaleX
y0 = ChartHeight * (prevPoint.y - Yorigin) / ScaleY
'y1 = ChartHeight * (prevPoint.ATTRAVERAGE - Yorigin) / ScaleY
x = ChartWidth * (myPoint.x - Xorigin) / ScaleX
y = ChartHeight * (myPoint.y - Yorigin) / ScaleY
'y2 = ChartHeight * (myPoint.ATTRAVERAGE - Yorigin) / ScaleY
g.DrawLine(bluePen, x0, y0, x, y)
g.FillEllipse(blueBrush, x0 - 2, y0 - 2, 6, 6)
g.FillEllipse(blueBrush, x - 2, y - 2, 6, 6)
End If
prevPoint = myPoint
i = i + 1
下一篇
b.Save(p.Response.OutputStream, ImageFormat.Jpeg)
b.Dispose()
‘ 您在 ASPX 页面传递文件名时取消注释此代码 2005 年 11 月 18 日
'b.Save("d:\Graph\Absent.gif", ImageFormat.Gif)
''''开始此代码行将输出保存为指定位置的图像
'Try
' b.Save(filename, ImageFormat.Gif)
' b.Dispose()
'Catch ex As Exception
' 'Response.Write("error:" & ex.Message.ToString)
'End Try
''''结束此代码行将输出保存为指定位置的图像
End Sub
Public Sub DrawAverage()
Dim i As Integer
Dim x As Single
Dim y As Single
Dim x0 As Single
Dim y0 As Single
Dim PrintAonDot As Integer
Dim myLabel As String
Dim d1 As String
Dim m1, m2, m3 As String
Dim blackPen As Pen = New Pen(Color.Black, 1)
Dim bluePen As Pen = New Pen(Color.Blue, 1)
Dim blueBrush As Brush = New SolidBrush(Color.Blue)
Dim blackBrush As Brush = New SolidBrush(Color.Black)
Dim axesFont As Font = New Font("verdana", 8, FontStyle.Bold)
p.Response.ContentType = "image/jpeg"
'g.FillRectangle(New SolidBrush(Color.LightYellow), 0, 0, Width, Height)
g.FillRectangle(New SolidBrush(Color.FromArgb(255, 216, 189)), 0, 0, Width, Height)
'Dim ChartInset As Integer = 50 旧测试更改
Dim ChartInset As Integer = 50
Dim ChartWidth As Integer = Width - (2 * ChartInset)
Dim ChartHeight As Integer = Height - (2 * ChartInset)
g.DrawRectangle(New Pen(Color.Blue, 1), ChartInset, ChartInset, ChartWidth, ChartHeight)
'g.DrawString(Title, New Font("arial", 14), blackBrush, Width / 3, 10)
g.DrawString(Title, New Font("verdana", 8, FontStyle.Bold), blueBrush, Width / 6, 5)
i = 0
i = 0
While i <= Xdivs
x = ChartInset + (i * ChartWidth) / Xdivs
y = ChartHeight + ChartInset
' 此代码用于在格式中打印X轴值
If i >= chartValues.Count Then
myLabel = "周数->" & vbCrLf & " "
'g.DrawString(myLabel, axesFont, blueBrush, x - 17, y + 10)
Else
'myLabel = CType(chartValues(i - 1), datapoint).xCaption 更改
myLabel = CType(chartValues(i), datapoint).xCaption
d1 = myLabel.Substring(0, 2).ToString
m1 = myLabel.Substring(3, 3).ToString
myLabel = d1 & vbCrLf & m1
End If
g.DrawString(myLabel, axesFont, blackBrush, x - 8, y + 10)
g.DrawLine(blackPen, x, y + 2, x, y - 2)
If i < chartValues.Count And i >= 3 Then
'' 打印平均离职率百分比到点上
myLabel = CType(chartValues(i), datapoint).ATTRAVERAGE
x = (ChartWidth * (CType(chartValues(i), datapoint).x - Xorigin) / ScaleX) + ChartInset
y = ChartHeight - (ChartHeight * (CType(chartValues(i), datapoint).y - Yorigin) / ScaleY) + ChartInset - 15
g.DrawString(myLabel, axesFont, blackBrush, x, y)
''End 打印平均离职率百分比到点上
End If
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
i = 0
i = 0
While i <= Ydivs
x = ChartInset
y = ChartHeight + ChartInset - (i * ChartHeight / Ydivs)
myLabel = (Yorigin + (ScaleY * i / Ydivs)).ToString & "%"
'g.DrawString(myLabel, axesFont, blackBrush, 5, y - 6) 旧测试更改
g.DrawString(myLabel, axesFont, blackBrush, 25, y - 6)
g.DrawLine(blackPen, x + 2, y, x - 2, y)
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
g.RotateTransform(180)
g.TranslateTransform(0, -Height)
g.TranslateTransform(-ChartInset, ChartInset)
g.ScaleTransform(-1, 1)
Dim prevPoint As datapoint = New datapoint
prevPoint.valid = False
i = 0
For Each myPoint As datapoint In chartValues
If prevPoint.valid = True Then
x0 = ChartWidth * (prevPoint.x - Xorigin) / ScaleX
y0 = ChartHeight * (prevPoint.y - Yorigin) / ScaleY
x = ChartWidth * (myPoint.x - Xorigin) / ScaleX
y = ChartHeight * (myPoint.y - Yorigin) / ScaleY
'If CType(chartValues(i), datapoint).ATTRAVERAGE.Trim > 0 Then
'g.DrawLine(bluePen, x0, y0, x, y)
'End If
If i >= 3 Then
g.DrawLine(bluePen, x0, y0, x, y)
g.FillEllipse(blueBrush, x0 - 2, y0 - 2, 6, 6)
g.FillEllipse(blueBrush, x - 2, y - 2, 6, 6)
End If
i = i + 1
End If
'myLabel = myPoint.yCaption
'g.DrawString(myLabel, axesFont, blackBrush, x0 + 1, y0 + 1)
prevPoint = myPoint
下一篇
b.Save(p.Response.OutputStream, ImageFormat.Jpeg)
End Sub
Protected Overrides Sub Finalize()
g.Dispose()
b.Dispose()
End Sub
End Class
*************************************************************************************************
2) 为此创建一个ASPX页面,名为Display.aspx,用于创建LineChart函数。
*********************************************************************
‘导入这些命名空间
Imports System.Data
Imports System.Data.OracleClient
‘ 变量声明
Dim orclCommand As OracleCommand
Dim rdr As OracleDataReader
Private OraCn As New OracleConnection(ConfigurationSettings.AppSettings("connString")) 'OracleConnection()
'注意:Web窗体设计器需要以下占位符声明。
'请勿删除或移动它。
Private designerPlaceholderDeclaration As System.Object
Dim Itm As ListItem
Dim Sqlstr As String
‘该页面的Page_Load事件
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If Not Page.IsPostBack Then
Session("numSelIndex") = 0
Sqlstr = "用于获取日期范围的SQL查询"
OraCn.Open()
orclCommand = New OracleCommand(Sqlstr, OraCn)
rdr = orclCommand.ExecuteReader
Itm = New ListItem
Itm.Text = "---选择---"
Itm.Value = ""
Itm.Selected = True
CmbFrWeek.Items.Add(Itm)
CmbToWeek.Items.Add(Itm)
While rdr.Read
Itm = New ListItem
Itm.Text = rdr.GetValue(0)
Itm.Value = rdr.GetValue(0)
CmbFrWeek.Items.Add(Itm)
CmbToWeek.Items.Add(Itm)
End While
rdr.Close()
OraCn.Close()
End If
End Sub
Private SubBtnReport_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnReport.Click
Dim NoOfWeek As Integer
Dim Enddate, M As String
Dim StartDate, Enddate1 As String
Dim TotalPer, RowNo As Integer
Dim DynWdith As Integer
Dim XFromDate As String
Dim XFromDate1 As Integer
Dim YattritionPer, YattritionPerAvg As Double
Dim Grdflag As Boolean = True
试试
If CmbToWeek.SelectedIndex < 1 And CmbFrWeek.SelectedIndex < 1 Then
Label9.Text = "请选择正确的日期"
Label9.Visible = True
flgFormSubmit.Value = 0
Exit Sub
ElseIf (CmbToWeek.SelectedIndex - CmbFrWeek.SelectedIndex) < 4 Then
Label9.Text = "选择的日期应该超过5天"
flgFormSubmit.Value = 0
Label9.Visible = True
Exit Sub
ElseIf CmbToWeek.SelectedIndex <= CmbFrWeek.SelectedIndex Then
Label9.Text = "开始日期必须小于结束日期"
flgFormSubmit.Value = 0
Label9.Visible = True
Exit Sub
ElseIf (CmbToWeek.SelectedIndex - CmbFrWeek.SelectedIndex) > 31 Then
Label9.Text = "日期不能选择超过一个月"
Label9.Visible = True
flgFormSubmit.Value = 0
Exit Sub
Else
Label9.Text = ""
End If
Label9.Text = ""
If CmbFrWeek.SelectedIndex = 1 Then
Enddate = "2003年5月24日"
Else
Enddate = CmbFrWeek.Items(CmbFrWeek.SelectedIndex - 1).Value
End If
NoOfWeek = (CmbToWeek.SelectedIndex - CmbFrWeek.SelectedIndex) + 2
' 此代码用于
OraCn.Open()
‘创建用于存储图形主数据的全局临时表
'将显示在折线图中的表格
Dim cmd As New OracleCommand("Proc_Absent_New", OraCn)
cmd.CommandType = CommandType.StoredProcedure
Dim FromWeek As OracleParameter = cmd.Parameters.Add("frmDay", OracleType.DateTime)
FromWeek.Direction = ParameterDirection.Input
FromWeek.Value = UCase(Trim(Enddate.ToString()))
Dim NoOfWeeks As OracleParameter = cmd.Parameters.Add("NoOfDays", OracleType.Int32, 20)
NoOfWeeks.Direction = ParameterDirection.Input
NoOfWeeks.Value = UCase(Trim(NoOfWeek.ToString()))
cmd.ExecuteNonQuery()
cmd.Dispose()
‘创建用于存储图形主数据的全局临时表
'将显示在折线图中的表格
Sqlstr = "SELECT COUNT(*)RowNo,ROUND(MAX(absentper)+1) FROM ABSENT_TEMP "
'OraCn.Open()
orclCommand = New OracleCommand(Sqlstr, OraCn)
rdr = orclCommand.ExecuteReader
While rdr.Read()
TotalPer = rdr.GetValue(1)
DynWdith = rdr.GetValue(1)
RowNo = rdr.GetValue(0)
End While
rdr.Close()
orclCommand.Dispose()
'****此代码用于绘图类声明对象
'****从临时表中选择值
Sqlstr = "select Fromday,ABSENTPER, rownum,to_char(Fromday, 'dd-Mon') fdate from ABSENT_TEMP "
orclCommand = New OracleCommand(Sqlstr, OraCn)
rdr = orclCommand.ExecuteReader
StartDate = CmbToWeek.Items(CmbToWeek.SelectedIndex).Value
Enddate1 = CmbFrWeek.Items(CmbFrWeek.SelectedIndex).Value
‘创建我们之前创建的折线图类的对象
Dim c1 As LineChartAbs = New LineChartAbs(RowNo * 50, 550, Page)
c1.Title = " 缺勤图 " & vbCrLf & " " & Convert.ToDateTime(Enddate1).ToString("dd/MM/yyyy") & "-" & Convert.ToDateTime(StartDate).ToString("dd/MM/yyyy")
c1.Xorigin = 0
c1.ScaleX = NoOfWeek - 0
c1.Xdivs = NoOfWeek - 0
c1.Yorigin = 0
If TotalPer > 12 Then
c1.ScaleY = Math.Ceiling(TotalPer / 10) * 10
c1.Ydivs = CInt((Math.Ceiling(TotalPer / 10) * 10))
Else
c1.ScaleY = TotalPer '如果缺勤百分比小于10%,则实现此比例
c1.Ydivs = CInt(TotalPer) * 5
End If
'c1.ScaleY = 100
'c1.Ydivs = 50
While rdr.Read
XFromDate = rdr.GetValue(2) - 1
XFromDate1 = CType(XFromDate, Integer) * 1
YattritionPer = rdr.GetValue(1)
c1.AddValue(XFromDate1, YattritionPer, rdr.GetValue(3), rdr.GetValue(1))
End While
rdr.Close()
c1.Draw()
''''开始此代码行将输出保存为指定位置的图像
Dim strFilePath, strUser As String
Dim strPath As String
Session("login") = "Absenteesimg"
strUser = Session("login")
试试
strFilePath = Server.MapPath(".") & "/Graphs/" & strUser & ".gif"
Catch ex As Exception
Response.Write("Error:" & ex.Message.ToString)
End Try
c1.Draw(strFilePath)
Response.Redirect("Graph.aspx")
'在此结束,正确显示
Catch ex As Exception
Response.Write("Error Occured" & ex.StackTrace)
最后
OraCn.Close()
'Label9.Text = ""
'Session("numSelIndex") = CmbToWeek.SelectedIndex
'Session("formsubmit") = 0
End Try
End Sub
End Class
******************************************************************************
3) 创建一个名为Graph.aspx的文件,并写入以下代码。
在此页面中调用由上一个Display ASPX页面生成的Generate Graph。
'**********************************************************************
在其中放置一个图像控件,并调用已保存的图形。
IMG TAGE设置图像的路径。
src="Graphs\Absenteesimg.gif"
优点:
1) 多个用户可以同时访问。
2) 根据用户会话生成图像(图表)。
3) 以报表形式将gif图像与数据导出到Excel文件。
4) 为每个用户请求生成动态图表。
数据的图形表示,使用户更容易理解系统数据的输出。
*****************************************************************************
可能的增强功能
CreatePieChart 函数缺乏第三方图形组件可能带来的冲击力和吸引力,但该函数仅用不到15分钟的时间就创建出来了,成本为零(除了我的时间),最重要的是,源代码随处可见,方便您进行任何未来的修改或增强。
CreatePieChart 函数的一个可能增强之处是添加传递SQL字符串而不是数据库表名的功能。目前,CreatePieChart 图只能为具有非常简单数据模型的数据库创建饼图。能够指定SQL字符串意味着您可以创建来自多个表的数据的图表,或者通过指定WHERE子句来仅绘制数据库表中的某些行。