Magazine Internet

[ASP] Dessiner une jauge en GDI+

Publié le 13 mars 2009 par Jeremy.jeanson

Utiliser GDI+ et ASP .net! Mais pourquoi donc?

Parfois il est plus simple d’afficher une image que de taper le code HTML permettant un rendu bien précis. C’est la cas par exemple quand on souhaite afficher des graphiques… la moindre modification de la mise en page se transforme en cauchemar. C’est alors qu’arrive l’ami GDI sur son beau cheval blanc. Pour ceux qui ne connaitrait pas GDI, faisons simple : il s’agit de la librairie utilisé par windows pour faire la plus part de ses rendu visuels, interfaces winform et images.

Cela faisait quelques temps que je n’avais pas fait ce genre de choses, alors voici un petit exemple de ce qui peut être fait pour afficher une image représentant un jauge.

Mais avant de commencer, voici un échantillons de ce qui peut être obtenu avec le code suivant.

Jauge

Pour commencer, GDI devant écrire dans la Stream de l’objet Response si on l’utilise tel quel, notre sortie comportera le binaire d’une image et notre navigateur n’affichera que celle-ci (un peu comme quand on ecrit un fichier sur la Stream de Response). Donc l’idée est d’utiliser un Handler qui se chargerai de retourner un Response utiliser comme source (src) d’une balise image (img). Pour y arriver j’écrit donc une classe implémentant l’interface IHttpHnadler et je change mon fichier de configuration afin qu’il prenne en compte ce Handler.

  <system.web>
    <authorization>
      <deny users="*"/>
    </authorization>
    <httpHandlers>
      <add verb="GET" 
           path="Jauge.axd"
           type="MonNameSpace.Jauge, MonNameSpace"
           />
    </httpHandlers>
  </system.web>
  <location path="Jauge.axd">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>

J’en ai profiter pour ajouter les droits d’accès au Handler, afin dans le cas d’une authentification Forms de m’assurer que l’accès à celui-ci est possible.

Note : Dans le cas où vous utiliseriez IIS7 sachez que ce dernier (pat défaut) préfèrera que vous créiez une fichier (jauge.axd) qu’un handler dans le fichier de config.

Notre jauge serra utilisable sous la forme d’un control dont l’utilisation via ASP .net se ferra sous la forme suivante

<%@ Register Assembly="MonNameSpace" Namespace="MonNameSpace" TagPrefix="ctrl" %>

<ctrl:Jauge runat="server" ID="MaJaugeQueJAimeBeaucoup" Valeur="2000" Valeurtotal="8000"></ctrl:Jauge>

Passons maintenant aux soses sérieuses, le code GDI ;)

Vb

Namespace MonNameSpace

    <ToolboxData("<{0}:Jauge runat=server></{0}:Jauge>")>
    Public Class Jauge 
	 Inherits WebControl
	 Implements IHttpHandler

	Private _valeur As Int32
	Private _valeurTotale As Int32

	''' <summary>
        ''' Valeur de la jauge
        ''' </summary>
        Public Property Valeur As Int32
            Get
            	Return Me._valeur
            End Get
            Set(ByVal value As Int32)
            	Me._valeur = value
            End Set
	End property

        ''' <summary>
        ''' Valeur maximum de la jauge
        ''' </summary>
        Public Int32 ValeurTotale
            Get 
		return Me._valeurTotale
            End Get 
            Set(ByVal value As Int32)
		Me._valeurTotale = value
            End Set
        End property

        ''' <summary>
        ''' Rendu du control
        ''' </summary>
        ''' <param name="writer"></param>
        Protected Override Sub Render(ByVal writer As HtmlTextWriter)
            writer.WriteLine( _
                String.Format( _
                    "<img src='Jauge.axd?value={0}&max={1}' alt='Jauge' border='0' />", _
                    Me._valeur, _
                    Me._valeurTotale))
        End Sub

        Private Const _width As Int32 = 600 
        Private Const _height As Int32 = 17
        Private Const _margeInterneJauge As Int32 = 2
        Private Const _graduationTop As Int32 = _height
        Private Const _graduationHeight As Int32 = 4
        Private Const _margeBord As Int32 = 40

        Public Property IsReusable As Boolean ' IHttpHandler
            Get 
            	Return False
            End Get
        End Property

        Public Sub ProcessRequest(ByVal context As HttpContext) ' IHttpHandler
            ' Largeur de l'image
            Dim value As Int32 = Convert.ToInt32(context.Request("value"))
            Dim max As Int32 = Convert.ToInt32(context.Request("max"))

            ' Zone de déssin
            Dim bmp As New Bitmap(_width, _height + 40)

            ' Control de dessin
            Dim g As New Graphics.FromImage(bmp)

            ' Progression de la barre 
            Dim rectJauge As New Rectangle( _
                _margeBord, _
                0, _
                _width - 1 - _margeBord*2, _
                _height - 1)
            Dim progress As Int32 = (value * rectJauge.Width) / max
            Dim rectProgess As New Rectangle( _
                rectJauge.X+ _margeInterneJauge, _
                rectJauge.Y +_margeInterneJauge, _
                progress - (_margeInterneJauge * 2), _
                rectJauge.Height - _margeInterneJauge * 2)

            ' Fond
            g.Clear(Color.White)

            ' Jauge
            g.FillRectangle(Brushes.Gray, rectJauge)
            g.DrawRectangle(Pens.Black, rectJauge)
            
            ' Remplire la jauge
            Me.PaintBackAeroGlass(g, rectProgess, System.Drawing.Color.LawnGreen, Nothing)

            ' Graduations
            DrawGraduation(g, rectJauge.X, 0)
            DrawGraduation(g, rectJauge.X + rectJauge.Width / 4, max / 4)
            DrawGraduation(g, rectJauge.X + rectJauge.Width / 2, max / 2)
            DrawGraduation(g, rectJauge.X + rectJauge.Width * 3 / 4, max * 3 / 4)
            DrawGraduation(g, rectJauge.X + rectJauge.Width, max)

            bmp.Save( _
                context.Response.OutputStream, _
                System.Drawing.Imaging.ImageFormat.Jpeg)
        End Sub

        ''' <summary>
        ''' Dessiner une graduation
        ''' </summary>
        ''' <param name="g"></param>
        ''' <param name="x"></param>
        ''' <param name="value"></param>
        Private Sub DrawGraduation(ByVal g As Graphics, ByVal x As Int32,ByVal value As Int32)

            g.DrawLine(Pens.Black, x, _graduationTop, x, _graduationTop + _graduationHeight)
            g.DrawString( _
                value.ToString(), _
                New Font("Verdana", 12), _
                Brushes.Black, _
                x, _
                _graduationTop + _graduationHeight + 10, _
                New StringFormat With { _
                    .Alignment = StringAlignment.Center, _
                    .LineAlignment = StringAlignment.Center })
        End Sub

        ''' <summary>
        ''' Fond type Aéro glass
        ''' </summary>
        ''' <param name="vG"></param>
        ''' <param name="vRect"></param>
        ''' <param name="vColor"></param>
        ''' <param name="vMasque"></param>
        Public Sub PaintBackAeroGlass(ByVal graphics As Graphics,ByVal zone As Rectangle, ByVal couleur As Color, ByVal masque As GraphicsPath)
            Dim Int_Heiht As Int32 
            Dim rect1, rect2 As Rectangle

            Dim brush1 As LinearGradientBrush = Nothing
            Dim brush2 As LinearGradientBrush = Nothing

            Try
                Int_Heiht = Convert.ToInt32(zone.Height / 2)
                rect1 = New Rectangle(zone.X, zone.Y, zone.Width, Int_Heiht)
                rect2 = New Rectangle(zone.X, zone.Y + Int_Heiht, zone.Width, zone.Height - Int_Heiht)

                brush1 = New LinearGradientBrush( _
                    rect1, _
                    Color.FromArgb(50, couleur), _
                    Color.FromArgb(160, couleur), _
                    LinearGradientMode.Vertical)

                brush2 = New LinearGradientBrush( _
                    rect2, _
                    Color.FromArgb(190, couleur), _
                    Color.FromArgb(210, couleur), _
                    LinearGradientMode.Vertical)

                ' Paint des 2 rect
                If masque Is Nothing Then

                    ' sans masque
                    graphics.FillRectangle(new SolidBrush(Color.White), zone)
                    graphics.FillRectangle(brush1, rect1)
                    graphics.FillRectangle(brush2, rect2)

                Else

                    Region r = null
                    Try
                        ' Avec masque
                        graphics.FillPath(New SolidBrush(Color.White), masque)

                        r = New Region(masque)
                        r.Intersect(rect1)
                        graphics.FillRegion(brush1, r)

                        r = New Region(masque)
                        r.Intersect(rect2)
                        graphics.FillRegion(brush2, r)

                    Finally

                        //Libération mémoire
                        if (r != null) r.Dispose();
                        r = null;
                    End Try
                End If

            Catch

            Finally
                if brush1 IsNot Nothing Then brush1.Dispose()
                brush1 = Nothing
                if brush2 IsNot Nothing Then brush2.Dispose()
                brush2 = Nothing
            End Try
        End Sub
End Namespace

C#

namespace MonNameSpace
{
    [ToolboxData("<{0}:Jauge runat=server></{0}:Jauge>")]
    public class Jauge : WebControl, IHttpHandler
    {
		private Int32 _valeur;
		private Int32 _valeurTotale;

		/// <summary>
        /// Valeur de la jauge
        /// </summary>
        public Int32 Valeur
        {
            get { return this._valeur; }
            set { this._valeur = value; }
        }

        /// <summary>
        /// Valeur maximum de la jauge
        /// </summary>
        public Int32 ValeurTotale
        {
            get { return this._valeurTotale; }
            set { this._valeurTotale = value; }
        }

        /// <summary>
        /// Rendu du control
        /// </summary>
        /// <param name="writer"></param>
        protected override void Render(HtmlTextWriter writer)
        {
            writer.WriteLine(
                String.Format(
                    @"<img src='Jauge.axd?value={0}&max={1}' alt='Jauge' border='0' />",
                    this._valeur ,
                    this._valeurTotale));
        }

        private const Int32 _width = 600;
        private const Int32 _height = 17;
        private const Int32 _margeInterneJauge = 2;
        private const Int32 _graduationTop = _height;
        private const Int32 _graduationHeight = 4;
        private const Int32 _margeBord = 40;

        public Boolean IsReusable //IHttpHandler
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context) //IHttpHandler
        {
            // Largeur de l'image
            Int32 value = Convert.ToInt32(context.Request["value"]);
            Int32 max = Convert.ToInt32(context.Request["max"]);

            // Zone de déssin
            Bitmap bmp = new Bitmap(_width, _height + 40);

            // Control de dessin
            Graphics g = Graphics.FromImage(bmp);

            // Progression de la barre 
            Rectangle rectJauge = new Rectangle(
                _margeBord,
                0,
                _width - 1 - _margeBord*2,
                _height - 1);
            Int32 progress = (value * rectJauge.Width) / max;
            Rectangle rectProgess = new Rectangle(
                rectJauge.X+ _margeInterneJauge,
                rectJauge.Y +_margeInterneJauge,
                progress - (_margeInterneJauge * 2), 
               rectJauge.Height - _margeInterneJauge * 2);

            // Fond
            g.Clear(Color.White);

            // Jauge
            g.FillRectangle(Brushes.Gray, rectJauge);
            g.DrawRectangle(Pens.Black, rectJauge);
            
            // Remplire la jauge
            this.PaintBackAeroGlass(g, rectProgess, System.Drawing.Color.LawnGreen, null);

            // Graduations
            DrawGraduation(g, rectJauge.X, 0);
            DrawGraduation(g, rectJauge.X + rectJauge.Width / 4, max / 4);
            DrawGraduation(g, rectJauge.X + rectJauge.Width / 2, max / 2);
            DrawGraduation(g, rectJauge.X + rectJauge.Width * 3 / 4, max * 3 / 4);
            DrawGraduation(g, rectJauge.X + rectJauge.Width, max);

            bmp.Save(
                context.Response.OutputStream,
                System.Drawing.Imaging.ImageFormat.Jpeg);
        }

        /// <summary>
        /// Dessiner une graduation
        /// </summary>
        /// <param name="g"></param>
        /// <param name="x"></param>
        /// <param name="value"></param>
        private void DrawGraduation(Graphics g, Int32 x,Int32 value)
        {
            g.DrawLine(Pens.Black, x, _graduationTop, x, _graduationTop + _graduationHeight);
            g.DrawString(
                value.ToString(),
                new Font("Verdana", 12),
                Brushes.Black,
                x,
                _graduationTop + _graduationHeight + 10,
                new StringFormat() { 
                    Alignment = StringAlignment.Center, 
                    LineAlignment = StringAlignment.Center });
        }

        /// <summary>
        /// Font type Aéro glass
        /// </summary>
        /// <param name="vG"></param>
        /// <param name="vRect"></param>
        /// <param name="vColor"></param>
        /// <param name="vMasque"></param>
        private void PaintBackAeroGlass(Graphics graphics, Rectangle zone, Color couleur, GraphicsPath masque)
        {
            Int32 Int_Heiht;
            Rectangle rect1, rect2;

            LinearGradientBrush
                brush1 = null,
                brush2 = null;

            try
            {
                Int_Heiht = Convert.ToInt32(zone.Height / 2);
                rect1 = new Rectangle(zone.X, zone.Y, zone.Width, Int_Heiht);
                rect2 = new Rectangle(zone.X, zone.Y + Int_Heiht, zone.Width, zone.Height - Int_Heiht);

                brush1 = new LinearGradientBrush(
                    rect1,
                    Color.FromArgb(50, couleur),
                    Color.FromArgb(160, couleur),
                    LinearGradientMode.Vertical);

                brush2 = new LinearGradientBrush(
                    rect2,
                    Color.FromArgb(190, couleur),
                    Color.FromArgb(210, couleur),
                    LinearGradientMode.Vertical);

                //Paint des 2 rect
                if (masque == null)
                {
                    //sans masque
                    graphics.FillRectangle(new SolidBrush(Color.White), zone);
                    graphics.FillRectangle(brush1, rect1);
                    graphics.FillRectangle(brush2, rect2);
                }
                else
                {
                    Region r = null;
                    try
                    {
                        //Avec masque
                        graphics.FillPath(new SolidBrush(Color.White), masque);

                        r = new Region(masque);
                        r.Intersect(rect1);
                        graphics.FillRegion(brush1, r);

                        r = new Region(masque);
                        r.Intersect(rect2);
                        graphics.FillRegion(brush2, r);
                    }
                    finally
                    {
                        //Libération mémoire
                        if (r != null) r.Dispose();
                        r = null;
                    }
                }
            }
            catch { }
            finally
            {
                if (brush1 != null) brush1.Dispose();
                brush1 = null;
                if (brush2 != null) brush2.Dispose();
                brush2 = null;
            }
        }
    }
}

Retour à La Une de Logo Paperblog

A propos de l’auteur


Jeremy.jeanson 1573 partages Voir son profil
Voir son blog

l'auteur n'a pas encore renseigné son compte l'auteur n'a pas encore renseigné son compte