Imports Microsoft.VisualBasic
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Web
Public Class JThermometer
'---These contants govern placement of the chart components on the target image.
' To change the layout of the chart, the constant values will need to be updated appropriately.
Private Const MARGIN_TOP As Integer = 20 '---Amount of space between top of image and top of title text
Private Const MARGIN_BOTTOM As Integer = 20 '---Amount of space between the bottom of the thermometer and the
' bottom of the image.
Private Const MARGIN_LEFT As Integer = 20 '---Left position of the actual value
Private Const TITLE_BOTTOMMARGIN = 55 '---Amount of space between top of title text and top of thermometer
Private Const OUTERBAR_TOP As Integer = _
MARGIN_TOP + TITLE_BOTTOMMARGIN '---Amount of space between top of image and top of thermometer
'---Bounds of elipse for curve at top of thermometer.
Private Const OUTERBAR_WIDTH As Integer = 30
Private Const OUTERBAR_ARCHEIGHT As Integer = 30
'---Bounds of elipse for thermometer bulb
Private Const OUTERBULB_WIDTH As Integer = 60
Private Const OUTERBULB_HEIGHT As Integer = 50
'---Bounds of elipse for curve at top of mercury
Private Const INNERBAR_WIDTH = 18
Private Const INNERBAR_ARCHEIGHT As Integer = 30
Private Const INNERBAR_TOPMARGIN = 10 '---Amount of space between top of mercury and top of thermometer
Private Const INNERBAR_BULBMARGIN = 10 '---Amount of space between thermometer bulb and mercury bulb.
'---Bounds of elipse for mercury bulb
Private Const INNERBULB_WIDTH As Integer = 40
Private Const INNERBULB_HEIGHT As Integer = 35
Private Const AXIS_MARGIN As Integer = 0 '---Distance of the axis indicators from the thermometer
Private Const AXIS_IN1_WIDTH As Integer = 35 '---Width of the primary indicator
Private Const AXIS_IN2_WIDTH As Integer = 20 '---Width of the secondary indicator
Private TitleColor As Color = Color.Gray '---Color of the title text
Private ActualValueColor As Color = Color.Gray '---Color of the actual value text
Private IndicatedValueColor As Color = Color.Gray '---Color of the indicated value text
Private miThermoCenter As Integer = 190 '---X position of the center of the thermometer within the image
Private miWidth As Integer = 240 '---Width of the image
Private miHeight As Integer = 400 '---Height of the image
Private miOuterbar_Height = _
miHeight - (MARGIN_TOP + TITLE_BOTTOMMARGIN + OUTERBULB_HEIGHT) '---Height of the thermometer
Private miInnerbar_Height = _
miOuterbar_Height - (INNERBAR_BULBMARGIN + (INNERBAR_ARCHEIGHT / 2)) '---Maximum height of the mercury
'---The ValueType enum affects the formatting of value text (IE: whether decimal places and the currency sign are displayed.
Public Enum ValueType As Integer
[Currency] = 1
[Decimal] = 2
[Integer] = 3
End Enum
''' <summary>
''' Outputs a thermometer image to the response stream
''' </summary>
''' <param name="dMinValue">Min value displayed on the thermometer</param>
''' <param name="dMaxValue">Max value displayed on the thermometer</param>
''' <param name="dIndicatedValue">Indicated value of the thermometer.</param>
''' <param name="sTitle">Title displayed at the top of the thermometer</param>
''' <param name="iValueType">Value type (controls how numbers are formatted. See above)</param>
''' <remarks></remarks>
Public Sub New( _
ByVal dMinValue As Decimal, _
ByVal dMaxValue As Decimal, _
ByVal dIndicatedValue As Decimal, _
ByVal sTitle As String, _
ByVal iValueType As ValueType)
ShowThermometer(dMinValue, dMaxValue, dIndicatedValue, sTitle, iValueType)
End Sub
''' <summary>
''' Displays the thermometer
''' </summary>
''' <param name="dMin">Min value to display on thermometer</param>
''' <param name="dMax">Max value to display on thermometer</param>
''' <param name="dValue">Indicated value to display on thermometer</param>
''' <param name="sTitle">Title to display at top of chart</param>
''' <param name="iType">Type of value to be displayed</param>
''' <remarks></remarks>
Private Sub ShowThermometer( _
ByVal dMin As Decimal, _
ByVal dMax As Decimal, _
ByVal dValue As Decimal, _
ByVal sTitle As String, _
ByVal iType As ValueType)
Dim dAdjValue As Decimal = dValue
If dValue < dMin Then
dAdjValue = dMin
ElseIf dValue > dMax Then
dAdjValue = dMax
Else
dAdjValue = dValue - dMin
End If
Dim dPercent As Decimal = dAdjValue / (dMax - dMin)
'---Create new image for composite
Dim oImage As Bitmap = New Bitmap(miWidth, miHeight, PixelFormat.Format24bppRgb)
'---Paste in the parts
Dim oG As Graphics = Graphics.FromImage(oImage)
'---Initialize graphic
oG.FillRectangle(New SolidBrush(Color.White), New Rectangle(0, 0, miWidth, miHeight))
'---Draw thermometer
DrawThermometer(oG)
DrawMercury(oG, dPercent)
DrawTitle(oG, sTitle)
ShowAxisValues(oG, dMin, dMax, 10, 3, iType)
DrawActualValue(oG, dValue, iType)
HttpContext.Current.Response.ContentType = "image/Gif"
oImage.Save(HttpContext.Current.Response.OutputStream, ImageFormat.Gif)
oG.Dispose()
oImage.Dispose()
End Sub
''' <summary>
''' Draws the thermometer (border without interior mercury)
''' </summary>
''' <param name="oGraphic">Graphic on which to do the drawing</param>
''' <remarks></remarks>
Private Sub DrawThermometer( _
ByRef oGraphic As Graphics)
Dim iCenterX As Integer = miThermoCenter
Dim iTopY As Integer = OUTERBAR_TOP
Dim iBottomY As Integer = miHeight - MARGIN_BOTTOM
Dim iOuterX_Left As Integer = iCenterX - (OUTERBAR_WIDTH / 2)
Dim iOuterX_Right As Integer = iCenterX + (OUTERBAR_WIDTH / 2)
Dim iOuterYArc_Top As Integer = iTopY
Dim iOuterYArc_Bottom As Integer = iTopY + (OUTERBAR_ARCHEIGHT / 2)
'---Draw top arc
oGraphic.DrawArc(New Pen(Color.Black), iOuterX_Left, iTopY, OUTERBAR_WIDTH, OUTERBAR_ARCHEIGHT, 180, 180)
'---Draw lines on each side
oGraphic.DrawLine(New Pen(Color.Black), iOuterX_Left, iOuterYArc_Bottom, iOuterX_Left, (iOuterYArc_Bottom + (miOuterbar_Height - OUTERBAR_ARCHEIGHT)))
oGraphic.DrawLine(New Pen(Color.Black), iOuterX_Right, iOuterYArc_Bottom, iOuterX_Right, (iOuterYArc_Bottom + (miOuterbar_Height - OUTERBAR_ARCHEIGHT)))
'---Draw bulb at bottom
Dim iBulb_Left As Integer = iCenterX - OUTERBULB_WIDTH / 2
Dim iBulb_Top As Integer = iOuterYArc_Bottom + (miOuterbar_Height - OUTERBAR_ARCHEIGHT) - 2
oGraphic.DrawArc( _
New Pen(Color.Black), _
iBulb_Left, _
iBulb_Top, _
OUTERBULB_WIDTH, _
OUTERBULB_HEIGHT, _
304, _
292)
End Sub
''' <summary>
''' Draws the mercury indicator inside the thermometer.
''' </summary>
''' <param name="oGraphic">Graphic on which to do the drawing</param>
''' <param name="dFillPercent">Percent of the thermometer that is filled (0.0-1.0)</param>
''' <remarks></remarks>
Private Sub DrawMercury( _
ByRef oGraphic As Graphics, _
ByRef dFillPercent As Decimal)
Dim iFillTop As Integer = miInnerbar_Height - (miInnerbar_Height * dFillPercent) + OUTERBAR_TOP + INNERBAR_TOPMARGIN
Dim iFillHeight As Integer = (miInnerbar_Height * dFillPercent)
Dim iCenterX As Integer = miThermoCenter
Dim iTopY As Integer = OUTERBAR_TOP + INNERBAR_TOPMARGIN
Dim iBottomY As Integer = miHeight - MARGIN_BOTTOM
Dim iInnerX_Left As Integer = iCenterX - (INNERBAR_WIDTH / 2)
Dim iInnerX_Right As Integer = iCenterX + (INNERBAR_WIDTH / 2)
Dim iInnerYArc_Top As Integer = iFillTop
Dim iInnerYArc_Bottom As Integer = iFillTop + (INNERBAR_ARCHEIGHT / 2)
'---For bulb at bottom
Dim iBulb_Left As Integer = iCenterX - INNERBULB_WIDTH / 2
Dim iBulb_Top As Integer = iTopY + miInnerbar_Height
'---Shadow
'---Draw top arc
oGraphic.FillEllipse( _
New SolidBrush(Color.DarkRed), _
iInnerX_Left - 1, _
iFillTop, _
INNERBAR_WIDTH + 1, _
INNERBAR_ARCHEIGHT)
oGraphic.FillEllipse( _
New SolidBrush(Color.DarkRed), _
iBulb_Left, _
iBulb_Top, _
INNERBULB_WIDTH, _
INNERBULB_HEIGHT)
'---Draw Bar
oGraphic.FillRectangle( _
New SolidBrush(Color.DarkRed), _
iInnerX_Left, _
CInt(iFillTop + (INNERBAR_ARCHEIGHT / 2)), _
INNERBAR_WIDTH, _
iFillHeight)
'---Actual
'---Draw top arc
oGraphic.FillEllipse( _
New SolidBrush(Color.Red), _
iInnerX_Left + 3, _
iFillTop + 4, _
INNERBAR_WIDTH - 6, _
INNERBAR_ARCHEIGHT - 6)
oGraphic.FillEllipse( _
New SolidBrush(Color.Red), _
iBulb_Left + 3, _
iBulb_Top + 3, _
INNERBULB_WIDTH - 6, _
INNERBULB_HEIGHT - 6)
'---Draw Bar
oGraphic.FillRectangle( _
New SolidBrush(Color.Red), _
iInnerX_Left + 3, _
CInt(iFillTop + (INNERBAR_ARCHEIGHT / 2)), _
INNERBAR_WIDTH - 6, _
iFillHeight)
'---Draw bulb
oGraphic.DrawEllipse( _
New Pen(Color.IndianRed), _
iBulb_Left + 3, _
iBulb_Top + 3, _
INNERBULB_WIDTH - 5, _
INNERBULB_HEIGHT - 5)
End Sub
''' <summary>
''' Draws the title text
''' </summary>
''' <param name="oGraphic">Graphic on which to do the drawing</param>
''' <param name="sText">Text of title</param>
''' <remarks></remarks>
Private Sub DrawTitle( _
ByRef oGraphic As Graphics, _
ByVal sText As String)
Dim oBrush As New System.Drawing.SolidBrush(TitleColor)
Dim oFont As New Font("Arial", 14, FontStyle.Bold)
Dim oSize As New SizeF
oSize = oGraphic.MeasureString(sText, oFont)
Dim iX As Integer = miWidth / 2 - oSize.Width / 2
Dim iY As Integer = MARGIN_TOP
oGraphic.DrawString(sText, _
oFont, _
oBrush, _
iX, iY, _
System.Drawing.StringFormat.GenericTypographic)
End Sub
''' <summary>
''' Draws the actual value
''' </summary>
''' <param name="oGraphic">Graphic on which to do the drawing</param>
''' <param name="dValue">The actual value</param>
''' <param name="iType">The type of the actual value</param>
''' <remarks></remarks>
Private Sub DrawActualValue( _
ByRef oGraphic As Graphics, _
ByVal dValue As Decimal, _
ByVal iType As ValueType)
Dim sText As String = NumberToText(dValue, iType)
Dim oBrush As New System.Drawing.SolidBrush(ActualValueColor)
Dim oFont As New Font("Arial", 14, FontStyle.Bold)
Dim oSize As New SizeF
oSize = oGraphic.MeasureString(sText, oFont)
Dim iX As Integer = MARGIN_LEFT
Dim iY As Integer = (miHeight - MARGIN_BOTTOM) - oSize.Height
oGraphic.DrawString(sText, _
oFont, _
oBrush, _
iX, _
iY, _
System.Drawing.StringFormat.GenericTypographic)
End Sub
''' <summary>
''' Draws the indicator lines and associated values
''' </summary>
''' <param name="oGraphic">Graphic on which to do the drawing</param>
''' <param name="dMin">Min value</param>
''' <param name="dMax">Max value</param>
''' <param name="iCount">Number of indicator values to display</param>
''' <param name="iShowMarkerInterval">Number of sub-interval markers to display for each interval</param>
''' <param name="iType">Type of value</param>
''' <remarks></remarks>
Private Sub ShowAxisValues( _
ByRef oGraphic As Graphics, _
ByVal dMin As Decimal, _
ByVal dMax As Decimal, _
ByVal iCount As Integer, _
ByVal iShowMarkerInterval As Integer, _
ByVal iType As ValueType)
Dim iXLeft1 As Integer = miThermoCenter - OUTERBAR_WIDTH / 2 - AXIS_IN1_WIDTH
Dim iXLeft2 As Integer = miThermoCenter - OUTERBAR_WIDTH / 2 - AXIS_IN2_WIDTH
Dim iXRight As Integer = miThermoCenter - OUTERBAR_WIDTH / 2 - AXIS_MARGIN
Dim dSpace As Decimal = miInnerbar_Height / iCount
Dim dSubSpace As Decimal = dSpace / (iShowMarkerInterval + 1)
Dim dValue As Decimal = (dMax - dMin) / iCount
Dim iYTop As Integer = OUTERBAR_TOP + INNERBAR_TOPMARGIN
For iIndicator As Integer = 0 To iCount
oGraphic.DrawLine(New Pen(Color.Black), iXLeft1, iYTop, iXRight, iYTop)
ShowAxisText(oGraphic, dMax - dValue * iIndicator, iXLeft1, iYTop, iType)
If iIndicator < iCount Then
For iSubIndicator As Integer = 1 To iShowMarkerInterval
oGraphic.DrawLine(New Pen(Color.Gray), iXLeft2, CInt(iYTop) + dSubSpace * iSubIndicator, iXRight, CInt(iYTop) + dSubSpace * iSubIndicator)
Next
End If
iYTop = iYTop + dSpace
Next
End Sub
''' <summary>
''' Displays the text of the indicator value.
''' </summary>
''' <param name="oGraphic">Graphic on which to do the drawing</param>
''' <param name="dValue">Indicator value</param>
''' <param name="iXRightPos">X position at which text should be right-aligned.</param>
''' <param name="iYCenter">Y position at which text should be centered</param>
''' <param name="iType">Type of text</param>
''' <remarks></remarks>
Private Sub ShowAxisText( _
ByRef oGraphic As Graphics, _
ByRef dValue As Decimal, _
ByRef iXRightPos As Integer, _
ByRef iYCenter As Integer, _
ByVal iType As ValueType)
Dim sText As String = NumberToText(dValue, iType)
Dim oBrush As New System.Drawing.SolidBrush(IndicatedValueColor)
Dim oFont As New Font("Arial", 11, FontStyle.Bold)
Dim oSize As New SizeF
oSize = oGraphic.MeasureString(sText, oFont)
Dim iX As Integer = iXRightPos - oSize.Width
Dim iY As Integer = iYCenter - oSize.Height / 2
oGraphic.DrawString(sText, _
oFont, _
oBrush, _
iX, _
iY, _
System.Drawing.StringFormat.GenericTypographic)
End Sub
''' <summary>
''' Formats value for display
''' </summary>
''' <param name="dValue">Value</param>
''' <param name="iType">Type of value</param>
''' <returns></returns>
''' <remarks></remarks>
Private Function NumberToText(ByVal dValue As Decimal, ByVal iType As ValueType) As String
Dim sText As String = ""
Select Case iType
Case ValueType.Currency
sText = FormatCurrency(dValue, 2, TriState.True, TriState.True, TriState.True)
Case ValueType.Decimal
sText = FormatNumber(dValue, 2, TriState.True, TriState.True, TriState.True)
Case ValueType.Integer
sText = CInt(dValue)
End Select
Return sText
End Function
End Class