9Deuce
9Deuce

Reputation: 676

MVC5 Live refresh Chart.js

I'm currently creating a dashboard to display information obtained from Google Analytics via Chart.js. The goal is to allow the user to choose metrics, dates, and an interval to graph, and the dashboard will call to Google and update the graph upon clicking a button. The dashboard is being created in Visual Studio 2013 in an MVC Application. The dashboard currently looks like this:Dashboard Sample The poorly-drawn box on the right is where I plan to put the button. The problem I'm having is creating the functionality for the button. I'm very very new to MVC, and I'm relatively certain that I've broken the logic, as I don't have a view. This app has basically become Controller to View. (This is what happens after dozens of MVC tutorials.

The Controller currently looks like so:

public enum Metrics{users, newUsers, percentNewSessions,  sessionsPerUser, sessions, bounces, bounceRate, sessionDuration, hits}

public enum Interval{Today, Yesterday, LastWeek, LastTwoWeeks, Daily, Weekly, Monthly, Yearly}

public class HomeController : Controller
{
    public ActionResult Index()
    {
        string accountEmailAddress = "[email protected]";
        string keyPath = Server.MapPath("path");
        var certificate = new X509Certificate2(keyPath, "blah", X509KeyStorageFlags.Exportable);//Creates certificate

        var credentials = new ServiceAccountCredential(
           new ServiceAccountCredential.Initializer(accountEmailAddress)
           {
               Scopes = new[] { AnalyticsService.Scope.AnalyticsReadonly }
           }.FromCertificate(certificate));//Creates credentials ot GA server

        AnalyticsService service = new AnalyticsService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credentials,
            ApplicationName = "Dash"
        });//Starts the service up.

        string profileId = "ga:59346790";
        string startDate = "2012-06-07";
        string endDate = "2015-02-17";
        string timing = "Yearly";
        string metrics = "ga:users";
        string[] dates = DateList(startDate, endDate, timing);
        List<string> ColumnName = new List<string>();
        List<double> values = new List<double>();
        if (timing.Equals("Daily"))
        {
            for (int i = 0; i < dates.Length - 1; i++)
            {
                DataResource.GaResource.GetRequest request = service.Data.Ga.Get(profileId, dates[i], dates[i], metrics);
                GaData data = request.Execute();
                ColumnName.Add(DateLabel(dates[i]));
                if (data.Rows == null)
                {
                    values.Add(0);
                }
                else
                {
                    foreach (var row in data.Rows)
                    {
                        foreach (var item in row)
                        {
                            values.Add(Convert.ToDouble(item));
                        }
                    }
                }
            }
        }
        else
        {
            for (int i = 0; i < dates.Length - 2; i+=2)
            {
                DataResource.GaResource.GetRequest request = service.Data.Ga.Get(profileId, dates[i], dates[i + 1], metrics);
                GaData data = request.Execute();
                ColumnName.Add(DateLabel(dates[i]));
                if (data.Rows == null)
                {
                    values.Add(0);
                }
                else
                {
                    foreach (var row in data.Rows)
                    {
                        foreach (var item in row)
                        {
                            values.Add(Convert.ToDouble(item));
                        }
                    }
                }
            }
        }
        List<Metrics> metricList = Enum.GetValues(typeof(Metrics)).Cast<Metrics>().ToList();
        List<Interval> intervalList = Enum.GetValues(typeof(Interval)).Cast<Interval>().ToList();
        ViewBag.Metrics = new SelectList(metricList);            
        ViewBag.Intervals = new SelectList(intervalList);
        values.OrderByDescending(m => values.Min());
        ViewBag.ColumnName = ColumnName.ToArray();
        ViewBag.Values = values.ToArray();
        int[] test = { 3, 5, 6, 7, 3, 8, 9 };
        ViewBag.intArray = test;
        string[] testLabel = { "This", "Is", "A", "Test", "You", "Got", "It?" };
        ViewBag.strArray = testLabel;
        return View();
    }

    private static string DateLabel(string date){ ....code}
    private static string[] DateList(string startDate, string endDate, string timing){...code}
}

This is my view: @{ ViewBag.Title = "Home Page";

double[] result = ViewBag.Values;
string[] labels = ViewBag.ColumnName;
string test = "";
string label = "";

for(int i =0; i<= result.Length - 1; ++i)
{
    if(i==0)
    {
        test = test + result[i].ToString();
    }
    else
    {
        test = test + "," + result[i].ToString();
    }
}

for (int i = 0; i <= labels.Length - 1; ++i)
{
    if (i == 0)
    {
        label = label + labels[i].ToString();
    }
    else
    {
        label = label + "," + labels[i].ToString();
    }
}
}
<label for="myChart">
    Google Analytics<br />
     <canvas id="myChart" width="800" height="400"></canvas>
 </label>
<div>
    <label for="Metrics">
        Metrics <br />
        @Html.DropDownList("Metrics", (SelectList)ViewBag.Metrics, new { @class = "form-control" })
    </label>
    <label for="Intervals">
        Interval<br />
        @Html.DropDownList("Intervals", (SelectList)ViewBag.Intervals, new { @class = "form-control" })
    </label>
    <label for="StartDate">
         Start Date<br />
        @Html.TextBox("StartDate")
    </label>
     <label for="EndDate">
        End Date<br />
        @Html.TextBox("EndDate")
    </label>
 </div>

<script>
var result = "@test";
var resultsArray = result.split(',');
var newLabels = "@label";
var labelsArray = newLabels.split(',');
var context = $("#myChart").get(0).getContext("2d");
var data = {
    labels: labelsArray,

    datasets: [{

        label: "My First dataset",
        fillColor: "rgba(220,220,220,0,2)",
        strokeColor: "rgba(220,220,220,1)",
        pointColor: "rgba(220,220,220,1)",
        pointStrokeColor: "#fff",
        pointHighlightFill: "#fff",
        pointHighlightStroke: "rgba(220,220,220,1)",
        data: resultsArray

    }]
}
var options = {
    ///Boolean - Whether grid lines are shown across the chart
    scaleShowGridLines: true,
    //String - Colour of the grid lines
    scaleGridLineColor: "rgba(0,0,0,.05)",
    //Number - Width of the grid lines
    scaleGridLineWidth: 1,
    //Boolean - Whether the line is curved between points
    bezierCurve: true,
    //Number - Tension of the bezier curve between points
    bezierCurveTension: 0.4,
    //Boolean - Whether to show a dot for each point
    pointDot: true,
    //Number - Radius of each point dot in pixels
    pointDotRadius: 4,
    //Number - Pixel width of point dot stroke
    pointDotStrokeWidth: 1,
    //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
    pointHitDetectionRadius: 20,
    //Boolean - Whether to show a stroke for datasets
    datasetStroke: true,
    //Number - Pixel width of dataset stroke
    datasetStrokeWidth: 2,
    //Boolean - Whether to fill the dataset with a colour
    datasetFill: true,

}
var myLineChart = new Chart(context).Line(data, options)

$(document).ready(function () {
    $('#StartDate').datepicker();
    $('#EndDate').datepicker();
});
</script>

If someone could show me how, with my current code, I could accomplish creating a button to live refresh the dashboard that would be great, although the code is kind of FUBAR as far as MVC standards go. I'm willing to accept gentle(or not so) nudges int he right direction.

Upvotes: 0

Views: 1687

Answers (1)

CoderDennis
CoderDennis

Reputation: 13837

Don't populate the chart data in your Controller's Index method or draw it when your view loads. Create a separate method (maybe even look at WebAPI for this) that only returns JSON data that you'll use to populate the chart. Call that method and refresh the chart in your button click. The JavaScript for populating the chart should also be in a separate file and not included within the text of your View. The chart will refresh without having to reload the entire page.

Google for AJAX if you want to know more about how this is done.

I would also consider using SignalR so that you don't need the button and the server can send new data to the chart as it becomes available, but that's probably an advanced technique.

Upvotes: 1

Related Questions