Search code examples
javascriptc#asp.netjsonmorris.js

Morris Chart with dynamic data from C#


I am trying to build a Morris graph in an ASP.NET web app, where the data that the graph is being populated with is coming from an ajax post to a C# method.

The return data is:

[{"process":"W3WP","xKey":"2018-8-1 7:00","yKey":"60"},
{"process":"Proc","xKey":"2018-8-1 7:00","yKey":"35"},
{"process":"W3WP","xKey":"2018-8-1 7:30","yKey":"75"},
{"process":"Proc","xKey":"2018-8-1 7:30","yKey":"30"},
{"process":"W3WP","xKey":"2018-8-1 8:00","yKey":"70"},
{"process":"Proc","xKey":"2018-8-1 8:00","yKey":"39"},
{"process":"W3WP","xKey":"2018-8-1 8:30","yKey":"71"},
{"process":"Proc","xKey":"2018-8-1 8:30","yKey":"30"}]

Basically, I want a graph that shows CPU usage for a list (dynamic) of processes. Each process should be represented by a line. When I build the graph with the following JavaScript, the graph is not displaying correctly:

var procChart = new Morris.Line({
    element: 'chartProcesses',
    data: $.parseJSON(ProcGraph()),
    xkey: ['xKey'],
    ykeys: ['yKey'],
    labels: ['process'],
    hideHover: 'auto',
    resize: true
});

The JSON post is as follows:

function ProcGraph() {
    var data = "";

    $.ajax({
        type: 'POST',
        url: 'Servers.aspx/GetGraphData',
        dataType: 'json',
        async: false,
        contentType: "application/json; charset=utf-8",
        data: {},
        success: function (result) {                                            
            data = result.d;
            alert(data);
        },
        error: function (xhr, status, error) {
            alert(error);
        }
    });

    return data;
}

And finally, the C# class:

public class GraphChartData
{
    public string process { get; set; }
    public string xKey { get; set; }
    public string yKey { get; set; }

    public GraphChartData(string process, string _xKey, string _yKey)
    {
        this.process = process;
        this.xKey = _xKey;
        this.yKey = _yKey;
    }

    public GraphChartData()
    {
    }
}

Graph results as follows: Morris Graph


Solution

  • I made a WebMethod that simulates dynamic data:

    It generates a random number of lines and processes (between 2 and 5), then returns an object containing the labels, the yKeys and the data needed for the Morris Line graph.

    [WebMethod]
    public static object GetGraphData()
    {
        Random random = new Random();
    
        List<Dictionary<string, object>> processes = new List<Dictionary<string, object>>();
        List<string> labels = new List<string>();
        List<string> yKeys = new List<string>();
        bool labelsDone = false;
    
        int nbLines = random.Next(2, 5);
        int nbProcesses = random.Next(2, 5);
    
        for (int i = 0; i < nbLines; i++)
        {
            Dictionary<string, object> processLine = new Dictionary<string, object>();
    
            string time = DateTime.Now.AddMinutes(i).ToString();
    
            processLine.Add("datetime", time);
    
            for (int j = 0; j < nbProcesses; j++)
            {
                processLine.Add($"processName{j + 1}", random.Next(100));
    
                if (!labelsDone)
                {
                    labels.Add($"Process Name{j + 1}");
                    yKeys.Add($"processName{j + 1}");
                }
            }
    
            labelsDone = true;
    
            processes.Add(processLine);
        }
    
        return new
        {
            labels = labels,
            ykeys = yKeys,
            processes = processes
        };
    }
    

    JavaScript code used to get data from the WebMethod GetGraphData:

    $(document).ready(function () {
        ProcGraph();
    });
    
    function ProcGraph() {
        var data = "";
        $.ajax({
            type: 'POST',
            url: 'Servers.aspx/GetGraphData',
            dataType: 'json',
            contentType: "application/json; charset=utf-8",
            data: {},
            success: function (result) {
                data = result.d;
               SetMorris(data)
            },
            error: function (xhr, status, error) {
                alert(error);
            }
        });
    
        return data;
    }
    
    function SetMorris(data) {
        var procChart = new Morris.Line({
            element: 'chartProcesses',
            data: data.processes,
            xkey: ['datetime'],
            ykeys: data.ykeys,
            labels: data.labels,
            hideHover: 'auto',
            resize: true,
            parseTime: false
        });
    }
    

    Please try the following snippet using data generated from the WebMethod:

    var data =
    [
        { "datetime": "14/08/2018 14:41:28", "processName1": 2, "processName2": 50 },
        { "datetime": "14/08/2018 14:42:28", "processName1": 20, "processName2": 34 },
        { "datetime": "14/08/2018 14:43:28", "processName1": 17, "processName2": 81 },
        { "datetime": "14/08/2018 14:44:28", "processName1": 86, "processName2": 67 }
    ]
    
    var procChart = new Morris.Line({
        element: 'chartProcesses',
        data : data,
        xkey: ['datetime'],
        ykeys: ['processName1', 'processName2'],
        labels: ['ProcessName1', "Process Name1"],
        hideHover: 'auto',
        resize: true,
        parseTime: false
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css" rel="stylesheet"/>
    
    <div id="chartProcesses"></div>

    Make sure to set the parseTime attribute to false:

    parseTime: false