First: Keep in mind that I spent about 30 minutes doing the conversation etc etc. I didn't clean up the code. I found it useful when creating a generic handler in asp.net as it was intent to better understand building Generic Hanlders for the Image control. Here's what I did:
I added an image control to my page in Visual Studio 2012. Then I create a Generic Handler and called it FundraisingGoalsHandler.ashx. After that, I converted the source from this project to C# and added to FundraisingGoalsHandler.ashx.
For the Image control on my page I added the following ImageUrl (pointed to the FundraisingGoalsHandler.ashx...and walla! It worked. :
imgThermometer.ImageUrl = "FundraisingGoalsHandler.ashx";
Past this code into FundraisingGoalsHanlder.ashx:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace MyProjectNamespace
{
/// <summary>
/// Summary description for FundraisingGoalsHandler
/// </summary>
public class FundraisingGoalsHandler : IHttpHandler
{
//---Amount of space between top of image and top of title text
private const int MARGIN_TOP = 20;
//---Amount of space between the bottom of the thermometer and the
private const int MARGIN_BOTTOM = 20;
// bottom of the image.
//---Left position of the actual value
private const int MARGIN_LEFT = 20;
//---Amount of space between top of title text and top of thermometer
private const int TITLE_BOTTOMMARGIN = 55;
//---Amount of space between top of image and top of thermometer
private const int OUTERBAR_TOP = MARGIN_TOP + TITLE_BOTTOMMARGIN;
//---Bounds of elipse for curve at top of thermometer.
private const int OUTERBAR_WIDTH = 30;
private const int OUTERBAR_ARCHEIGHT = 30;
//---Bounds of elipse for thermometer bulb
private const int OUTERBULB_WIDTH = 60;
private const int OUTERBULB_HEIGHT = 50;
//---Bounds of elipse for curve at top of mercury
private const int INNERBAR_WIDTH = 18;
private const int INNERBAR_ARCHEIGHT = 30;
//---Amount of space between top of mercury and top of thermometer
private const int INNERBAR_TOPMARGIN = 10;
//---Amount of space between thermometer bulb and mercury bulb.
private const int INNERBAR_BULBMARGIN = 10;
//---Bounds of elipse for mercury bulb
private const int INNERBULB_WIDTH = 40;
private const int INNERBULB_HEIGHT = 35;
//---Distance of the axis indicators from the thermometer
private const int AXIS_MARGIN = 0;
//---Width of the primary indicator
private const int AXIS_IN1_WIDTH = 35;
//---Width of the secondary indicator
private const int AXIS_IN2_WIDTH = 20;
//---Color of the title text
private Color TitleColor = Color.Gray;
//---Color of the actual value text
private Color ActualValueColor = Color.Gray;
//---Color of the indicated value text
private Color IndicatedValueColor = Color.Gray;
//---X position of the center of the thermometer within the image
private int miThermoCenter = 190;
//---Width of the image
private int miWidth = 240;
//---Height of the image
private int miHeight = 400;
//---Height of the thermometer
private int miOuterbar_Height = 265;
//---Maximum height of the mercury
private int miInnerbar_Height = 240;
//---The ValueType enum affects the formatting of value text (IE: whether decimal places and the currency sign are displayed.
public enum ValueType : int
{
Currency = 1,
Decimal = 2,
Integer = 3
}
/// <summary>
/// Draws the thermometer (border without interior mercury)
/// </summary>
/// <param name="oGraphic">Graphic on which to do the drawing</param>
/// <remarks></remarks>
private void DrawThermometer(ref Graphics oGraphic)
{
int iCenterX = miThermoCenter;
int iTopY = OUTERBAR_TOP;
int iBottomY = miHeight - MARGIN_BOTTOM;
int iOuterX_Left = iCenterX - (OUTERBAR_WIDTH / 2);
int iOuterX_Right = iCenterX + (OUTERBAR_WIDTH / 2);
int iOuterYArc_Top = iTopY;
int iOuterYArc_Bottom = 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
int iBulb_Left = iCenterX - OUTERBULB_WIDTH / 2;
int iBulb_Top = iOuterYArc_Bottom + (miOuterbar_Height - OUTERBAR_ARCHEIGHT) - 2;
oGraphic.DrawArc(new Pen(Color.Black), iBulb_Left, iBulb_Top, OUTERBULB_WIDTH, OUTERBULB_HEIGHT, 304, 292);
}
/// <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 void DrawMercury(ref Graphics oGraphic, ref float dFillPercent)
{
int iFillHeight = Convert.ToInt16(miInnerbar_Height * dFillPercent);
int iFillTop = miInnerbar_Height - iFillHeight + OUTERBAR_TOP + INNERBAR_TOPMARGIN;
int iCenterX = miThermoCenter;
int iTopY = OUTERBAR_TOP + INNERBAR_TOPMARGIN;
int iBottomY = miHeight - MARGIN_BOTTOM;
int iInnerX_Left = iCenterX - (INNERBAR_WIDTH / 2);
int iInnerX_Right = iCenterX + (INNERBAR_WIDTH / 2);
int iInnerYArc_Top = iFillTop;
int iInnerYArc_Bottom = iFillTop + (INNERBAR_ARCHEIGHT / 2);
//---For bulb at bottom
int iBulb_Left = iCenterX - INNERBULB_WIDTH / 2;
int iBulb_Top = 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, Convert.ToInt32(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, Convert.ToInt32(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);
}
/// <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 void DrawTitle(ref Graphics oGraphic, string sText)
{
System.Drawing.SolidBrush oBrush = new System.Drawing.SolidBrush(TitleColor);
Font oFont = new Font("Arial", 14, FontStyle.Bold);
SizeF oSize = new SizeF();
oSize = oGraphic.MeasureString(sText, oFont);
float iX = 240 / 2 - oSize.Width / 2;
float iY = 20;
oGraphic.DrawString(sText, oFont, oBrush, iX, iY, System.Drawing.StringFormat.GenericTypographic);
}
/// <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 void DrawActualValue(ref Graphics oGraphic, float dValue, ValueType iType)
{
string sText = dValue.ToString("C");
System.Drawing.SolidBrush oBrush = new System.Drawing.SolidBrush(ActualValueColor);
Font oFont = new Font("Arial", 14, FontStyle.Bold);
SizeF oSize = new SizeF();
oSize = oGraphic.MeasureString(sText, oFont);
float iX = MARGIN_LEFT;
float iY = 380 - oSize.Height;
oGraphic.DrawString(sText, oFont, oBrush, iX, iY, System.Drawing.StringFormat.GenericTypographic);
}
/// <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 void ShowAxisValues(ref Graphics oGraphic, float dMin, float dMax, int iCount, int iShowMarkerInterval, ValueType iType)
{
int iXLeft1 = miThermoCenter - OUTERBAR_WIDTH / 2 - AXIS_IN1_WIDTH;
float iXLeft2 = miThermoCenter - OUTERBAR_WIDTH / 2 - AXIS_IN2_WIDTH;
float iXRight = miThermoCenter - OUTERBAR_WIDTH / 2 - AXIS_MARGIN;
float dSpace = miInnerbar_Height / iCount;
float dSubSpace = dSpace / (iShowMarkerInterval + 1);
float dValue = (dMax - dMin) / iCount;
int iYTop = OUTERBAR_TOP + INNERBAR_TOPMARGIN;
float myRefVariable;
float myOtherVariable;
for (int iIndicator = 0; iIndicator <= iCount; iIndicator++)
{
myRefVariable = dMax - (Convert.ToSingle(dValue) * iIndicator);
oGraphic.DrawLine(new Pen(Color.Black), iXLeft1, iYTop, iXRight, iYTop);
ShowAxisText(ref oGraphic, ref myRefVariable, ref iXLeft1, ref iYTop, iType);
if (iIndicator < iCount)
{
for (int iSubIndicator = 1; iSubIndicator <= iShowMarkerInterval; iSubIndicator++)
{
myOtherVariable = iYTop + dSubSpace * iSubIndicator;
oGraphic.DrawLine(new Pen(Color.Gray), iXLeft2, Convert.ToSingle(myOtherVariable), iXRight, Convert.ToInt32(iYTop) + dSubSpace * iSubIndicator);
}
}
iYTop = Convert.ToInt16(iYTop + dSpace);
}
}
/// <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 void ShowAxisText(ref Graphics oGraphic, ref float dValue, ref int iXRightPos, ref int iYCenter, ValueType iType)
{
string sText = dValue.ToString("C");
System.Drawing.SolidBrush oBrush = new System.Drawing.SolidBrush(IndicatedValueColor);
Font oFont = new Font("Arial", 11, FontStyle.Bold);
SizeF oSize = new SizeF();
oSize = oGraphic.MeasureString(sText, oFont);
float iX = iXRightPos - oSize.Width;
float iY = iYCenter - oSize.Height / 2;
oGraphic.DrawString(sText, oFont, oBrush, iX, iY, System.Drawing.StringFormat.GenericTypographic);
}
/// <summary>
/// Formats value for display
/// </summary>
/// <param name="dValue">Value</param>
/// <param name="iType">Type of value</param>
/// <returns></returns>
/// <remarks></remarks>
///
public string DecimalToWords(float d)
{
//Grab a string form of your decimal value ("12.34")
var formatted = d.ToString();
if (formatted.Contains("."))
{
//If it contains a decimal point, split it into both sides of the decimal
string[] sides = formatted.Split('.');
//Process each side and append them with "and", "dot" or "point" etc.
return NumberToText(Int32.Parse(sides[0])) + " and " + NumberToText(Int32.Parse(sides[1]));
}
else
{
//Else process as normal
return NumberToText(Convert.ToInt32(d));
}
}
public static string NumberToText(int number)
{
string words = "";
try
{
if (number == 0)
return "zero";
if (number < 0)
return "minus " + NumberToText(Math.Abs(number));
if ((number / 1000000) > 0)
{
words += NumberToText(number / 1000000) + " million ";
number %= 1000000;
}
if ((number / 1000) > 0)
{
words += NumberToText(number / 1000) + " thousand ";
number %= 1000;
}
if ((number / 100) > 0)
{
words += NumberToText(number / 100) + " hundred ";
number %= 100;
}
if (number > 0)
{
if (words != "")
words += "and ";
var unitsMap = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
var tensMap = new[] { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
if (number < 20)
words += unitsMap[Convert.ToInt16(number)];
else
{
words += tensMap[Convert.ToInt16(number) / 10];
if ((number % 10) > 0)
words += "-" + unitsMap[Convert.ToInt16(number) % 10];
}
}
}
catch (Exception ex)
{
words = "error";
}
return words;
}
/// <summary>
/// You will need to configure this handler in the Web.config file of your
/// web and register it with IIS before being able to use it. For more information
/// see the following link: http://go.microsoft.com/?linkid=8101007
/// </summary>
#region IHttpHandler Members
public bool IsReusable
{
// Return false in case your Managed Handler cannot be reused for another request.
// Usually this would be false in case you have some state information preserved per request.
get { return false ; }
}
public void ProcessRequest(HttpContext context)
{
//write your handler implementation here.
float dMin = 0;
float dMax = Convert.ToSingle(GlobalVars.Goal);
float dValue = Convert.ToSingle(GlobalVars.TotalRaised);
string sTitle = "Amount Raised";
ValueType iType = ValueType.Currency;
float dAdjValue = dValue;
if (dValue < dMin)
{
dAdjValue = dMin;
}
else if (dValue > dMax)
{
dAdjValue = dMax;
}
else
{
dAdjValue = dValue - dMin;
}
float dPercent = dAdjValue / (dMax - dMin);
//---Create new image for composite
Bitmap oImage = new Bitmap(miWidth, miHeight, PixelFormat.Format24bppRgb);
//---Paste in the parts
Graphics oG = Graphics.FromImage(oImage);
//---Initialize graphic
oG.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, miWidth, miHeight));
//---Draw thermometer
DrawThermometer(ref oG);
DrawMercury(ref oG, ref dPercent);
DrawTitle(ref oG, sTitle);
ShowAxisValues(ref oG, dMin, dMax, 10, 3, iType);
DrawActualValue(ref oG, dValue, iType);
context.Response.ContentType = "image/jpeg";
context.Response.BinaryWrite(BitmapDataFromBitmap((oImage), ImageFormat.Jpeg));
oG.Dispose();
oImage.Dispose();
}
static public byte[] BitmapDataFromBitmap(Bitmap objBitmap, ImageFormat imageFormat)
{
MemoryStream ms = new MemoryStream();
objBitmap.Save(ms, imageFormat);
return (ms.GetBuffer());
}
#endregion
}
}
|