ASP.NET Chart Controls y ASP.NET MVC 2

Hace ya más de un año apareció una nueva librería para la creación de gráficos, tanto para Web Forms como Win Forms, con una enorme cantidad de posibilidades. Hoy en día se nos puede plantear la posibilidad de utilizar estos mismos controles para una aplicación ASP.NET MVC y cómo sería la forma más sencilla de adaptarlo.
Si bien he leído y probado varias opciones, voy a escribir sobre la que me ha parecido más sencilla y más práctica.

Instalación de Librerías y componentes

Para poder trabajar con estos controles, es necesario descargar dos ejecutables:

La librería que nos permite la creación de un gráfico se llama System.Web.DataVisualization, la cual está disponible instalando el primero de los paquetes. El segundo de ellos es interesante instalarlo para poder visualizar en el cuadro de herramientas el control de tipo Chart. Existen numerosas combinaciones y propiedades configurables para este tipo de controles, por lo que hay veces que es más práctico crear una aplicación Web Forms de prueba, en modo diseño arrastrar el control y personalizarlo. De esta forma podemos ver el código generado en el aspx y las propiedades utilizadas para ese chart en concreto. Otra de las posibilidades es descargar el proyecto de ejemplos y localizar alguno que ya esté definido y adaptarlo.

CREACIÓN DEL GRÁFICO

Para entender mejor el código, podríamos decir que un chart se compone de 4 partes principalmente: Chart, que es el control principal, Legend, encargado de la leyenda del gráfico, ChartArea, el cual representa el área donde se mostrarán los valores y las Series que son los valores en sí.

El primer paso es agregar una referencia a la librería System.Web.DataVisualization. Una vez añadida, creamos una nueva acción donde se instanciarán los controles necesarios y, finalmente, nos devolverá la imagen generada según las propiedades establecidas.

public ActionResult GetChart()
{
    const string legend = "Legend";
    const string chartArea = "chartArea";

    var chart = ChartFactory.CreateChart("ASP.NET MVC and MSChart by GiS!");

    ChartFactory.CreateSerie(chart, "januarySeries", chartArea,
                            legend, "Emboss", Color.ForestGreen,
                            ChartValueType.DateTime, ChartValueType.Double,
                            _repository.GetMonthData(1));

    ChartFactory.CreateSerie(chart, "februarySeries", chartArea,
                            legend, "Cylinder", Color.DodgerBlue,
                            ChartValueType.DateTime, ChartValueType.Double,
                            _repository.GetMonthData(1));

    ChartFactory.CreateSerie(chart, "marchSeries", chartArea,
                            legend, "Wedge", Color.DarkViolet,
                            ChartValueType.DateTime, ChartValueType.Double,
                            _repository.GetMonthData(3));

    var memoryStream = new MemoryStream();
    chart.SaveImage(memoryStream);

    return File(memoryStream.GetBuffer(), @"image/png");
}

Para intentar refactorizar parte del código necesario para generar el gráfico, he creado una clase llamada ChartFactory en la cual podemos formar tanto el chart, la leyenda, el chartArea y las series que se mostrarán.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Web.UI.DataVisualization.Charting;
using ChartControlASPNETMVC.Models;

namespace ChartControlASPNETMVC
{
    public static class ChartFactory
    {
        public static Chart CreateChart(string chartTitle)
        {
            //Chart
            var chart = new Chart
                            {
                                Height = 296,
                                Width = 412,
                                BorderWidth = 2,
                                ImageType = ChartImageType.Png,
                                BackColor = ColorTranslator.FromHtml("#F3DFC1"),
                                BorderlineDashStyle = ChartDashStyle.Solid,
                                BackGradientStyle = GradientStyle.LeftRight,
                                BorderColor = Color.FromArgb(181, 64, 1),
                                BorderSkin = { SkinStyle = BorderSkinStyle.Sunken },
                            };

            //Title
            var title = chart.Titles.Add("chartTitle");
            title.ShadowColor = Color.FromArgb(32, 0, 0, 0);
            title.ShadowOffset = 3;
            title.ForeColor = Color.FromArgb(26, 59, 105);
            title.Font = new Font("Trebuchet MS", 14, FontStyle.Bold);
            title.Text = chartTitle;
            title.Alignment = ContentAlignment.TopLeft;

            //Legend
            var legend = chart.Legends.Add("chartLegend");
            legend.LegendStyle = LegendStyle.Row;
            legend.Font = new Font("Trebuchet MS", 10, FontStyle.Bold);
            legend.Enabled = true;
            legend.Name = "Legend";
            legend.BackColor = Color.Transparent;
            legend.Position.Y = 95;
            legend.Position.X = 5;
            legend.Position.Height = 20;
            legend.Position.Width = 100;

            //Chart Area
            var chartArea = chart.ChartAreas.Add("chartArea");
            chartArea.BorderColor = Color.FromArgb(64, 64, 64, 64);
            chartArea.BackSecondaryColor = Color.White;
            chartArea.BackColor = Color.OldLace;
            chartArea.ShadowColor = Color.Transparent;

            //Chart Area 3D Style
            chartArea.Area3DStyle.Enable3D = true;
            chartArea.Area3DStyle.Rotation = -20;
            chartArea.Area3DStyle.Perspective = 8;
            chartArea.Area3DStyle.Inclination = 18;
            chartArea.Area3DStyle.IsRightAngleAxes = false;
            chartArea.Area3DStyle.WallWidth = 0;
            chartArea.Area3DStyle.IsClustered = false;
            chartArea.Area3DStyle.PointDepth = 50;
            chartArea.Area3DStyle.PointGapDepth = 200;

            chartArea.AxisY.LineColor = Color.FromArgb(64, 64, 64, 64);
            chartArea.AxisY.IsLabelAutoFit = false;
            chartArea.AxisY.LabelStyle.Font = new Font("Trebuchet MS", 8, FontStyle.Bold);
            chartArea.AxisY.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);

            chartArea.AxisX.LineColor = Color.FromArgb(64, 64, 64, 64);
            chartArea.AxisX.IsLabelAutoFit = false;
            chartArea.AxisX.LabelStyle.Font = new Font("Trebuchet MS", 8, FontStyle.Bold);
            chartArea.AxisX.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);

            return chart;
        }
        public static void CreateSerie(Chart chart, string serieName, string chartAreaName, string legendName, string         drawingStyle, Color color, ChartValueType xValue, ChartValueType yValue, List<TableSample> monthData)
        {
            var newSerie = chart.Series.Add(serieName);
            newSerie.ChartArea = chartAreaName;
            newSerie.XValueType = xValue;
            newSerie.YValueType = yValue;
            newSerie.Name = serieName;
            newSerie.ShadowColor = Color.Transparent;
            newSerie.BorderColor = color;
            newSerie.Color = color;
            newSerie.Legend = legendName;

            /**** Drawing Style ****/
            /*Cylinder - Data points are drawn as cylinders.
            Emboss - Data points are drawn with an embossed effect.
            LightToDark - Data points are drawn with a light-to-dark effect.
            Wedge - Data points are drawn with a wedge effect.
            Default  - Data points are drawn as cubes.*/

            newSerie["DrawingStyle"] = drawingStyle;
            newSerie["PointWidth"] = "0.8";

            WriteSeries(newSerie, monthData);
        }

        private static void WriteSeries(Series serie, IEnumerable<TableSample> list)
        {
            foreach (TableSample t in list)
            {
                serie.Points.Add(new DataPoint
                                     {
                                         YValues = new Double[] { t.Amount },
                                         LegendText = t.Date.Day.ToString(),
                                         AxisLabel = t.Date.Day.ToString()
                                     });
            }
        }
    }
}

Este código es más que candidato a ser refactorizado y hacer una librería que nos permita mayor flexibilidad, pero el objetivo de este post es mostrar que existe la posibilidad de utilizar este tipo de controles.

La función de este control, a fin de cuentas, es generar una imagen con las propiedades y los datos obtenidos. Para llamar a la acción GetChart desde nuestra vista únicamente debemos asignar la misma al source de una imagen.


<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>
        <%= Html.Encode(ViewData["Message"]) %></h2>
    <div id="container">
        <img src="<%=Url.Action("GetChart") %>" alt="Chart Sample" />
    </div>
</asp:Content>

 Si arrancamos la aplicación, el resultado sería el siguiente:

Y, lo mejor de todo, el renderizado de la página:


!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd</a>">
html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>">
head><title>

   Home Page

</title><link href="Content/Site.css" rel="stylesheet" type="text/css" />

</head>
<body>
   <div>
       <div id="header">
           <div id="title">
               <h1>
                   My MVC Application</h1>
           </div>
           <div id="logindisplay">

       [ <a href="/Account/LogOn">Log On</a> ]

           </div>
           <div id="menucontainer">
               <ul id="menu">
                   <li>
                       <a href="/">Home</a></li>
                   <li>
                       <a href="/Home/About">About</a></li>
               </ul>
           </div>
       </div>
       <div id="main">

   <h2>
       Chart Control Sample!</h2>
   <div id="container">
       <img src="/Home/GetChart" alt="Chart Sample" />
   </div>

           <div id="footer">
           </div>
       </div>
   </div>
</body>
</html>

Por último, debido a que esta librería es adicional al framework, sería recomendable modificar las propiedades de la misma para tener una copia en el paquete final.

Adjunto el proyecto por si fuera de utilidad.

¡Saludos!

2 comentarios sobre “ASP.NET Chart Controls y ASP.NET MVC 2

  1. Compartido por Razor View Engine para ASP.NET MVC 3 | Return(GiS);

  2. Compartido por ¿que es cshtml? « Soloelectronicos

Deja un comentario