0

I have a MVC application, which creates a Chart in the business logic like this:

StatisticsModel.Chart.Width = 150
    StatisticsModel.Chart.Height = 300
    StatisticsModel.Chart.Attributes.Add("align", "left")

    StatisticsModel.Chart.Titles.Add("Statistics for: " + StatisticsModel.ProductNumbers)
    StatisticsModel.Chart.ChartAreas.Add(New ChartArea)

    StatisticsModel.Chart.Series.Add(New Series)

    StatisticsModel.Chart.Series(0).ChartType = SeriesChartType.Column

    StatisticsModel.Chart.Series(0).Points.DataBindXY(StatisticsModel.FailedTPDescriptionList, "key", StatisticsModel.FailedTPDescriptionList, "value")

Now, I am trying to implement it in the View, but I have read many articles, and they suggest me to put the chart in a different controller. But that would mean I have to send the Chart object there, as I have many functions, that require a chart, and I thought the easiest way is to implement it in the Model, and then rendering it from there.

I tried using: http://code-inside.de/blog-in/2008/11/27/howto-use-the-new-aspnet-chart-controls-with-aspnet-mvc/

But the:

@Code
Dim writer As New HtmlTextWriter(Page.Response.Output)
End Code

Didn't work for me. I am using VB.NET

Can anyone help me? Suggestions are very welcome.

1 Answer 1

2

There are many, many ways of creating and showing charts in MVC, and the link you referred to is pretty good IMHO. I'm using c#, but the way I'm doing it is to use an img-tag in the view and point the src-attribute to a Controller action:

<img id="diagram" src="<%=Url.Action("DrawChartImage", "Home") %>" alt="Chart Diagram" />

The controller action returns a FileContentResult:

public ActionResult DrawChartImage()
    {
        using (var chartHelper = new ChartHelper())
        {
            //get data
            var data = GetSomeDataForTheChart();

            //draw chart
            chartHelper.Draw(data);

            //return chart as png image
            return File(chartHelper.Image, "image/png");
        }
    }

The ChartHelper class implements IDisposable and has a helper property (Image) which returns the chart as a file, NOTE this is just sample/snippet code to show what I mean:

public class ChartHelper : IDisposable
{
    private readonly Chart _chart;
    public Chart Chart
    {
        get
        {
            return _chart;
        }
    }

    public byte[] Image
    {
        get
        {
            using (var ms = new MemoryStream())
            {
                _chart.SaveImage(ms);
                return ms.GetBuffer();
            }
        }
    }

    public ChartHelper()
    {
        _chart = new Chart();
        _chart.Height = 300;
        _chart.Width = 800;
        _chart.ImageType = ChartImageType.Png;
        _chart.Titles.Add("some title");
        _chart.Legends.Add("some legend");
        _chart.ChartAreas.Add("some chart area");
    }

    public void Draw(List<Data> data)
    {
        var dataArrays = GetDataArrays(data); //another helper method...

        var series = new Series(tag);
        series.Name = tag;
        series.Legend = "tags";
        series.ChartType = SeriesChartType.Spline;
        series.BorderWidth = 4;

        //sample way to add data below... 
        series.Points.DataBindXY(dataArrays.Item1, dataArrays.Item2);

        _chart.Series.Add(series);
    }

    public void Dispose()
    {
        _chart.Dispose();
    }
}

Works pretty well for me, hope it helps even if it's in C#.

EDIT If you want to create the image/chart in business logic called from your "main" Controller action, maybe you can do something like this where you generate the image/chart and then save it to disk, cache or database and pick it up from the image rendering controller action:

        public ActionResult Index()
    {
        //this is call to your business logic or similar which generates the chart
        byte[] image = GenerateImage();
        //save image to cache, disk or from database
        HttpContext.Cache["image"] = image;
        return View();
    }

    public ActionResult Image()
    {
        //get image from cache, disk or from database
        var image = HttpContext.Cache["image"] as byte[];
        return File(image, "image/png"); 
    }

    //some sample/dummy code to generate image from a template
    private byte[] GenerateImage()
    {
        using (var ms = new MemoryStream())
        {
            using (var image = System.Drawing.Image.FromFile(@"c:/temp/template.png"))
            using (var brush = new SolidBrush(System.Drawing.Color.Black))
            using (var bmp = new System.Drawing.Bitmap(image, image.Width, image.Height))
            using (var g = System.Drawing.Graphics.FromImage(bmp))
            {
                g.DrawString(DateTime.Now.ToLongTimeString(), new Font("Consolas", 10), brush, 10, 10);
                bmp.Save(ms, ImageFormat.Png);
            }
            return ms.ToArray();
        }
    }

And the view would be:

<img src="@Url.Action("Image")"/>
Sign up to request clarification or add additional context in comments.

7 Comments

But sending it to another action would require passing along the chart data. I have my chart logic in the business logic, and running that twice would be kind of bad for the performance of the application. I just need to display the chart on the View, when the Chart is already created at @Model.Chart
I see what you mean, and in that case I would create the chart and save it to disk or a database as an image with an unique file name or id in the business logic, and then use an img-tag in the view and refer to the image on disk OR a controller/action (like the sample above) which picks the image from the database and render it.
Added some sample code to show how it can be done differently, hope it helps :)
Thank you very much, that approach indeed seems a good way to go :) Might use the unique-ID feature of the MS Chart then, thank you ^^
I think that may have to do with the image being cached. There's a trick for that, by adding a date/time dummy parameter to the call for rendering the chart-image. I do it in javascript, using something like: diagram.src = "<%=Url.Action("DrawChartImage", "Home") %>?" + new Date(); but it can be done in various ways. The problem is the browser cache for sure.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.