Use Chart.js for graphs in HTML reports 81/65981/1
authorPatrice Buriez <patrice.buriez@intel.com>
Fri, 30 Nov 2018 11:16:43 +0000 (12:16 +0100)
committerPatrice Buriez <patrice.buriez@intel.com>
Wed, 19 Dec 2018 08:13:11 +0000 (09:13 +0100)
This JavaScript library is available under MIT license.

Also adjusted version for jQuery and jsTree,
and added fallback font-family names.

JIRA: YARDSTICK-1367
Topic: report/html_table (6 of 12)

Change-Id: Ibe8b7e3d1f1365d2cbc019bfc22762aaa365a4e1
Signed-off-by: Patrice Buriez <patrice.buriez@intel.com>
docs/testing/user/userguide/10-yardstick-user-interface.rst
yardstick/benchmark/core/report.py
yardstick/common/nsb_report.css
yardstick/common/nsb_report.html.j2
yardstick/common/report.html.j2

index 76890b2..5f94149 100644 (file)
@@ -27,8 +27,8 @@ Description
 
 The graph is framed with Timestamp on x-axis and output values
 (differ from testcase to testcase) on y-axis with the help of
-`Highcharts`_.
+`Chart.js`_.
 
 .. _InfluxDB: https://www.influxdata.com/time-series-platform/influxdb/
 .. _Jinja2: http://jinja.pocoo.org/docs/2.10/
-.. _Highcharts: https://www.highcharts.com/products/highcharts/
+.. _Chart.js: https://www.chartjs.org/
index a484a49..530fbf1 100644 (file)
@@ -135,7 +135,7 @@ class Report(object):
         self.db_task = self._get_tasks()
 
         field_keys = []
-        temp_series = []
+        datasets = []
         table_vals = {}
 
         field_keys = [encodeutils.to_utf8(field['fieldKey'])
@@ -143,7 +143,6 @@ class Report(object):
 
         for key in field_keys:
             self.Timestamp = []
-            series = {}
             values = []
             for task in self.db_task:
                 task_time = encodeutils.to_utf8(task['time'])
@@ -155,16 +154,14 @@ class Report(object):
                 task_time = head + "." + tail[:6]
                 self.Timestamp.append(task_time)
                 if task[key] is None:
-                    values.append('')
+                    values.append(None)
                 elif isinstance(task[key], (int, float)) is True:
                     values.append(task[key])
                 else:
                     values.append(ast.literal_eval(task[key]))
+            datasets.append({'label': key, 'data': values})
             table_vals['Timestamp'] = self.Timestamp
             table_vals[key] = values
-            series['name'] = key
-            series['data'] = values
-            temp_series.append(series)
 
         template_dir = consts.YARDSTICK_ROOT_PATH + "yardstick/common"
         template_environment = jinja2.Environment(
@@ -173,7 +170,7 @@ class Report(object):
             trim_blocks=False)
 
         context = {
-            "series": temp_series,
+            "datasets": datasets,
             "Timestamps": self.Timestamp,
             "task_id": self.task_id,
             "table": table_vals,
index 0c47791..2beb91c 100644 (file)
@@ -19,7 +19,7 @@ table {
 }
 
 header {
-    font-family: Frutiger;
+    font-family: Frutiger, "Helvetica Neue", Helvetica, Arial, sans-serif;
     clear: left;
     text-align: center;
 }
index f1b4ae1..0b4719b 100644 (file)
         <meta charset="utf-8">
         <meta name="viewport" content="width=device-width, initial-scale=1">
         <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
-        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.5/themes/default/style.min.css">
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/themes/default/style.min.css">
         <link rel="stylesheet" href="{{template_dir}}/nsb_report.css">
-        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
+        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
         <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
-        <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
-        <script src="https://code.highcharts.com/highcharts.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/jstree.min.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>
     </head>
 
     <body>
                     <h4>Report of {{task_id}} Generated</h4>
                 </header>
             </div>
-            <div class="row" style="height:500px">
+            <div class="row">
                 <div class="col-md-2 control-pane">
                     <div id="data_selector"></div>
                 </div>
                 <div class="col-md-10 data-pane">
-                    <div id="graph"></div>
+                    <canvas id="cnvGraph" style="width: 100%; height: 500px"></canvas>
                 </div>
             </div>
             <div class="row">
@@ -47,7 +47,8 @@
         </div>
 
         <script>
-            var arr, tab, tr, td, tbody, keys, key, curr_data;
+            var None = null;
+            var arr, tab, tr, td, tbody, keys, key, curr_data, val;
             arr = {{table|safe}};
 
             tab = document.getElementsByTagName('table')[0];
@@ -63,8 +64,9 @@
                 curr_data = arr[key];
                 // add each piece of data as its own column
                 for (var j = 0; j < curr_data.length; j++) {
+                    val = curr_data[j];
                     td = document.createElement('td');
-                    td.append(curr_data[j]);
+                    td.append(val === None ? '' : val);
                     tr.append(td);
                 }
                 tbody.append(tr);
                     },
                 });
 
-                $('#data_selector').on('check_node.jstree uncheck_node.jstree', function(e, data) {
-                    var selected_leaves = [];
-                    for (var i = 0; i < data.selected.length; i++) {
-                        var node = data.instance.get_node(data.selected[i]);
-                        if (node.children.length == 0) {
-                            var point = {name: node.id, data: arr[node.id]};
-                            selected_leaves.push(point);
-                        }
-                    }
-
-                    $('#graph').highcharts({
-                        title: {
-                            text: 'Yardstick Graphs',
-                            x: -20, //center
-                        },
-                        chart: {
-                            marginLeft: 400,
-                            zoomType: 'x',
-                            type: 'spline',
-                        },
-                        xAxis: {
-                            crosshair: {
-                                width: 1,
-                                color: 'black',
-                            },
-                            title: {
-                                text: 'Timestamp',
+                var objGraph = new Chart($('#cnvGraph'), {
+                    type: 'line',
+                    data: {
+                        labels: {{Timestamps|safe}},
+                        datasets: [],
+                    },
+                    options: {
+                        elements: {
+                            line: {
+                                borderWidth: 2,
+                                fill: false,
+                                tension: 0,
                             },
-                            categories: {{Timestamps|safe}},
                         },
-                        yAxis: {
-                            crosshair: {
-                                width: 1,
-                                color: 'black',
-                            },
-                            plotLines: [{
-                                value: 0,
-                                width: 1,
-                                color: '#808080',
+                        scales: {
+                            xAxes: [{
+                                type: 'category',
+                            }],
+                            yAxes: [{
+                                type: 'linear',
                             }],
                         },
-                        plotOptions: {
-                            series: {
-                                showCheckbox: false,
-                                visible: false,
-                            },
+                        tooltips: {
+                            mode: 'point',
+                            intersect: true,
                         },
-                        tooltip: {
-                            valueSuffix: '',
+                        hover: {
+                            mode: 'index',
+                            intersect: false,
+                            animationDuration: 0,
                         },
                         legend: {
-                            enabled: true,
+                            position: 'bottom',
+                            labels: {
+                                usePointStyle: true,
+                            },
                         },
-                        series: selected_leaves,
-                    });
+                        animation: {
+                            duration: 0,
+                        },
+                        responsive: true,
+                        responsiveAnimationDuration: 0,
+                        maintainAspectRatio: false,
+                    },
+                });
 
-                    var chart = $('#graph').highcharts();
-                    for (var i = 0; i < chart.series.length; i++) {
-                        var series = chart.series[i];
-                        if (series.visible) {
-                            series.hide();
-                        } else {
-                            series.show();
+                $('#data_selector').on('check_node.jstree uncheck_node.jstree', function(e, data) {
+                    var selected_datasets = [];
+                    for (var i = 0; i < data.selected.length; i++) {
+                        var node = data.instance.get_node(data.selected[i]);
+                        if (node.children.length == 0) {
+                            var dataset = {
+                                label: node.id,
+                                data: arr[node.id],
+                            };
+                            selected_datasets.push(dataset);
                         }
                     }
+
+                    var colors = [
+                        '#FF0000',  // Red
+                        '#228B22',  // ForestGreen
+                        '#FF8C00',  // DarkOrange
+                        '#00008B',  // DarkBlue
+                        '#FF00FF',  // Fuchsia
+                        '#9ACD32',  // YellowGreen
+                        '#FFD700',  // Gold
+                        '#4169E1',  // RoyalBlue
+                        '#A0522D',  // Sienna
+                        '#20B2AA',  // LightSeaGreen
+                        '#8A2BE2',  // BlueViolet
+                    ];
+
+                    var points = [
+                        {s: 'circle',   r: 3},
+                        {s: 'rect',     r: 4},
+                        {s: 'triangle', r: 4},
+                        {s: 'star',     r: 4},
+                        {s: 'rectRot',  r: 5},
+                    ];
+
+                    selected_datasets.forEach(function(d, i) {
+                        var color = colors[i % colors.length];
+                        var point = points[i % points.length];
+                        d.borderColor = color;
+                        d.backgroundColor = color;
+                        d.pointStyle = point.s;
+                        d.pointRadius = point.r;
+                        d.pointHoverRadius = point.r + 1;
+                    });
+                    objGraph.data.datasets = selected_datasets;
+                    objGraph.update();
                 });
             });
         </script>
index ab76510..1dc7b1d 100644 (file)
@@ -15,9 +15,9 @@
         <meta charset="utf-8">
         <meta name="viewport" content="width=device-width, initial-scale=1">
         <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
-        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
+        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
         <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
-        <script src="https://code.highcharts.com/highcharts.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>
 
         <style>
             table {
@@ -26,7 +26,7 @@
                 display: block;
             }
             header {
-                font-family: Frutiger;
+                font-family: Frutiger, "Helvetica Neue", Helvetica, Arial, sans-serif;
                 clear: left;
                 text-align: center;
             }
                     </div>
                 </div>
                 <div class="col-md-8">
-                    <div id="container"></div>
+                    <canvas id="cnvGraph" style="width: 100%; height: 500px"></canvas>
                 </div>
             </div>
         </div>
 
         <script>
-            var arr, tab, th, tr, td, tn, row, col, thead, tbody;
+            var None = null;
+            var arr, tab, th, tr, td, tn, row, col, thead, tbody, val;
             arr = {{table|safe}};
             tab = document.getElementsByTagName('table')[0];
 
                 tn = document.createTextNode(Object.keys(arr).sort()[col]);
                 th.appendChild(tn);
                 tr.appendChild(th);
-                thead.appendChild(tr);
             }
+            thead.appendChild(tr);
             tab.appendChild(thead);
 
             tbody = document.createElement('tbody');
             for (row = 0; row < arr[Object.keys(arr)[0]].length; row++) {
                 tr = document.createElement('tr');
                 for (col = 0; col < Object.keys(arr).length; col++) {
+                    val = arr[Object.keys(arr).sort()[col]][row];
                     td = document.createElement('td');
-                    tn = document.createTextNode(arr[Object.keys(arr).sort()[col]][row]);
+                    tn = document.createTextNode(val === None ? '' : val);
                     td.appendChild(tn);
                     tr.appendChild(td);
                 }
             tab.appendChild(tbody);
 
             $(function() {
-                $('#container').highcharts({
-                    title: {
-                        text: 'Yardstick test results',
-                        x: -20, //center
-                    },
-                    subtitle: {
-                        text: 'Report of {{task_id}} Task Generated',
-                        x: -20,
+                var datasets = {{datasets|safe}};
+
+                var colors = [
+                    '#FF0000',  // Red
+                    '#228B22',  // ForestGreen
+                    '#FF8C00',  // DarkOrange
+                    '#00008B',  // DarkBlue
+                    '#FF00FF',  // Fuchsia
+                    '#9ACD32',  // YellowGreen
+                    '#FFD700',  // Gold
+                    '#4169E1',  // RoyalBlue
+                    '#A0522D',  // Sienna
+                    '#20B2AA',  // LightSeaGreen
+                    '#8A2BE2',  // BlueViolet
+                ];
+
+                var points = [
+                    {s: 'circle',   r: 3},
+                    {s: 'rect',     r: 4},
+                    {s: 'triangle', r: 4},
+                    {s: 'star',     r: 4},
+                    {s: 'rectRot',  r: 5},
+                ];
+
+                datasets.forEach(function(d, i) {
+                    var color = colors[i % colors.length];
+                    var point = points[i % points.length];
+                    d.borderColor = color;
+                    d.backgroundColor = color;
+                    d.pointStyle = point.s;
+                    d.pointRadius = point.r;
+                    d.pointHoverRadius = point.r + 1;
+                });
+
+                new Chart($('#cnvGraph'), {
+                    type: 'line',
+                    data: {
+                        labels: {{Timestamps|safe}},
+                        datasets: datasets,
                     },
-                    xAxis: {
+                    options: {
+                        elements: {
+                            line: {
+                                borderWidth: 2,
+                                fill: false,
+                                tension: 0,
+                            },
+                        },
                         title: {
-                            text: 'Timestamp',
+                            text: [
+                                'Yardstick test results',
+                                'Report of {{task_id}} Task Generated',
+                            ],
+                            display: true,
                         },
-                        categories: {{Timestamps|safe}},
-                    },
-                    yAxis: {
-                        plotLines: [{
-                            value: 0,
-                            width: 1,
-                            color: '#808080',
-                        }],
-                    },
-                    tooltip: {
-                        valueSuffix: '',
-                    },
-                    legend: {
-                        layout: 'vertical',
-                        align: 'right',
-                        verticalAlign: 'middle',
-                        borderWidth: 0,
+                        scales: {
+                            xAxes: [{
+                                type: 'category',
+                                scaleLabel: {
+                                    display: true,
+                                    labelString: 'Timestamp',
+                                },
+                            }],
+                            yAxes: [{
+                                type: 'linear',
+                                scaleLabel: {
+                                    display: true,
+                                    labelString: 'Values',
+                                },
+                            }],
+                        },
+                        tooltips: {
+                            mode: 'point',
+                            intersect: true,
+                        },
+                        hover: {
+                            mode: 'index',
+                            intersect: false,
+                            animationDuration: 0,
+                        },
+                        legend: {
+                            position: 'right',
+                            labels: {
+                                usePointStyle: true,
+                            },
+                        },
+                        animation: {
+                            duration: 0,
+                        },
+                        responsive: true,
+                        responsiveAnimationDuration: 0,
+                        maintainAspectRatio: false,
                     },
-                    series: {{series|safe}},
                 });
             });
         </script>