Bump up ChartJs to 2.2.1 and AngularChart to 1.0

Change-Id: I9ac9e9fa381e63dbfa2c0cf715c4e1280dc80c2d
diff --git a/web/gui/src/main/webapp/tp/angular-chart.js b/web/gui/src/main/webapp/tp/angular-chart.js
index 4624343..26ac9fe 100755
--- a/web/gui/src/main/webapp/tp/angular-chart.js
+++ b/web/gui/src/main/webapp/tp/angular-chart.js
@@ -1,3 +1,12 @@
+/*!
+ * angular-chart.js - An angular.js wrapper for Chart.js
+ * http://jtblin.github.io/angular-chart.js/
+ * Version: 1.0.0
+ *
+ * Copyright 2016 Jerome Touffe-Blin
+ * Released under the BSD-2-Clause license
+ * https://github.com/jtblin/angular-chart.js/blob/master/LICENSE
+ */
 (function (factory) {
   'use strict';
   if (typeof exports === 'object') {
@@ -10,15 +19,19 @@
     define(['angular', 'chart'], factory);
   } else {
     // Browser globals
+    if (typeof angular === 'undefined' || typeof Chart === 'undefined')
+      throw new Error('Chart.js library needs to included, see http://jtblin.github.io/angular-chart.js/');
     factory(angular, Chart);
   }
 }(function (angular, Chart) {
   'use strict';
 
-  Chart.defaults.global.responsive = true;
   Chart.defaults.global.multiTooltipTemplate = '<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= value %>';
-
-  Chart.defaults.global.colours = [
+  Chart.defaults.global.tooltips.mode = 'label';
+  Chart.defaults.global.elements.line.borderWidth = 2;
+  Chart.defaults.global.elements.rectangle.borderWidth = 2;
+  Chart.defaults.global.legend.display = false;
+  Chart.defaults.global.colors = [
     '#97BBCD', // blue
     '#DCDCDC', // light grey
     '#F7464A', // red
@@ -28,34 +41,37 @@
     '#4D5360'  // dark grey
   ];
 
-  var usingExcanvas = typeof window.G_vmlCanvasManager === 'object' &&
+  var useExcanvas = typeof window.G_vmlCanvasManager === 'object' &&
     window.G_vmlCanvasManager !== null &&
     typeof window.G_vmlCanvasManager.initElement === 'function';
 
-  if (usingExcanvas) Chart.defaults.global.animation = false;
+  if (useExcanvas) Chart.defaults.global.animation = false;
 
   return angular.module('chart.js', [])
     .provider('ChartJs', ChartJsProvider)
     .factory('ChartJsFactory', ['ChartJs', '$timeout', ChartJsFactory])
     .directive('chartBase', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory(); }])
-    .directive('chartLine', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Line'); }])
-    .directive('chartBar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Bar'); }])
-    .directive('chartRadar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Radar'); }])
-    .directive('chartDoughnut', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Doughnut'); }])
-    .directive('chartPie', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Pie'); }])
-    .directive('chartPolarArea', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('PolarArea'); }]);
+    .directive('chartLine', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('line'); }])
+    .directive('chartBar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('bar'); }])
+    .directive('chartHorizontalBar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('horizontalBar'); }])
+    .directive('chartRadar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('radar'); }])
+    .directive('chartDoughnut', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('doughnut'); }])
+    .directive('chartPie', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('pie'); }])
+    .directive('chartPolarArea', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('polarArea'); }])
+    .directive('chartBubble', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('bubble'); }])
+    .name;
 
   /**
    * Wrapper for chart.js
    * Allows configuring chart js using the provider
    *
    * angular.module('myModule', ['chart.js']).config(function(ChartJsProvider) {
-   *   ChartJsProvider.setOptions({ responsive: true });
-   *   ChartJsProvider.setOptions('Line', { responsive: false });
+   *   ChartJsProvider.setOptions({ responsive: false });
+   *   ChartJsProvider.setOptions('Line', { responsive: true });
    * })))
    */
   function ChartJsProvider () {
-    var options = {};
+    var options = { responsive: true };
     var ChartJs = {
       Chart: Chart,
       getOptions: function (type) {
@@ -88,84 +104,52 @@
       return {
         restrict: 'CA',
         scope: {
-          data: '=?',
-          labels: '=?',
-          options: '=?',
-          series: '=?',
-          colours: '=?',
-          getColour: '=?',
+          chartGetColor: '=?',
           chartType: '=',
-          legend: '@',
-          click: '=?',
-          hover: '=?',
-
           chartData: '=?',
           chartLabels: '=?',
           chartOptions: '=?',
           chartSeries: '=?',
-          chartColours: '=?',
-          chartLegend: '@',
+          chartColors: '=?',
           chartClick: '=?',
-          chartHover: '=?'
+          chartHover: '=?',
+          chartDatasetOverride: '=?'
         },
         link: function (scope, elem/*, attrs */) {
-          var chart, container = document.createElement('div');
-          container.className = 'chart-container';
-          elem.replaceWith(container);
-          container.appendChild(elem[0]);
-
-          if (usingExcanvas) window.G_vmlCanvasManager.initElement(elem[0]);
-
-          ['data', 'labels', 'options', 'series', 'colours', 'legend', 'click', 'hover'].forEach(deprecated);
-          function aliasVar (fromName, toName) {
-            scope.$watch(fromName, function (newVal) {
-              if (typeof newVal === 'undefined') return;
-              scope[toName] = newVal;
-            });
-          }
-          /* provide backward compatibility to "old" directive names, by
-           * having an alias point from the new names to the old names. */
-          aliasVar('chartData', 'data');
-          aliasVar('chartLabels', 'labels');
-          aliasVar('chartOptions', 'options');
-          aliasVar('chartSeries', 'series');
-          aliasVar('chartColours', 'colours');
-          aliasVar('chartLegend', 'legend');
-          aliasVar('chartClick', 'click');
-          aliasVar('chartHover', 'hover');
+          if (useExcanvas) window.G_vmlCanvasManager.initElement(elem[0]);
 
           // Order of setting "watch" matter
+          scope.$watch('chartData', watchData, true);
+          scope.$watch('chartSeries', watchOther, true);
+          scope.$watch('chartLabels', watchOther, true);
+          scope.$watch('chartOptions', watchOther, true);
+          scope.$watch('chartColors', watchOther, true);
+          scope.$watch('chartDatasetOverride', watchOther, true);
+          scope.$watch('chartType', watchType, false);
 
-          scope.$watch('data', function (newVal, oldVal) {
+          scope.$on('$destroy', function () {
+            destroyChart(scope);
+          });
+
+          scope.$on('$resize', function () {
+            if (scope.chart) scope.chart.resize();
+          });
+
+          function watchData (newVal, oldVal) {
             if (! newVal || ! newVal.length || (Array.isArray(newVal[0]) && ! newVal[0].length)) {
-              destroyChart(chart, scope);
+              destroyChart(scope);
               return;
             }
             var chartType = type || scope.chartType;
             if (! chartType) return;
 
-            if (chart && canUpdateChart(newVal, oldVal))
-              return updateChart(chart, newVal, scope, elem);
+            if (scope.chart && canUpdateChart(newVal, oldVal))
+              return updateChart(newVal, scope);
 
-            createChart(chartType);
-          }, true);
+            createChart(chartType, scope, elem);
+          }
 
-          scope.$watch('series', resetChart, true);
-          scope.$watch('labels', resetChart, true);
-          scope.$watch('options', resetChart, true);
-          scope.$watch('colours', resetChart, true);
-
-          scope.$watch('chartType', function (newVal, oldVal) {
-            if (isEmpty(newVal)) return;
-            if (angular.equals(newVal, oldVal)) return;
-            createChart(newVal);
-          });
-
-          scope.$on('$destroy', function () {
-            destroyChart(chart, scope);
-          });
-
-          function resetChart (newVal, oldVal) {
+          function watchOther (newVal, oldVal) {
             if (isEmpty(newVal)) return;
             if (angular.equals(newVal, oldVal)) return;
             var chartType = type || scope.chartType;
@@ -173,50 +157,41 @@
 
             // chart.update() doesn't work for series and labels
             // so we have to re-create the chart entirely
-            createChart(chartType);
+            createChart(chartType, scope, elem);
           }
 
-          function createChart (type) {
-            if (isResponsive(type, scope) && elem[0].clientHeight === 0 && container.clientHeight === 0) {
-              return $timeout(function () {
-                createChart(type);
-              }, 50, false);
-            }
-            if (! scope.data || ! scope.data.length) return;
-            scope.getColour = typeof scope.getColour === 'function' ? scope.getColour : getRandomColour;
-            var colours = getColours(type, scope);
-            var cvs = elem[0], ctx = cvs.getContext('2d');
-            var data = Array.isArray(scope.data[0]) ?
-              getDataSets(scope.labels, scope.data, scope.series || [], colours) :
-              getData(scope.labels, scope.data, colours);
-            var options = angular.extend({}, ChartJs.getOptions(type), scope.options);
-
-            // Destroy old chart if it exists to avoid ghost charts issue
-            // https://github.com/jtblin/angular-chart.js/issues/187
-            destroyChart(chart, scope);
-            chart = new ChartJs.Chart(ctx)[type](data, options);
-            scope.$emit('create', chart);
-
-            // Bind events
-            cvs.onclick = scope.click ? getEventHandler(scope, chart, 'click', false) : angular.noop;
-            cvs.onmousemove = scope.hover ? getEventHandler(scope, chart, 'hover', true) : angular.noop;
-
-            if (scope.legend && scope.legend !== 'false') setLegend(elem, chart);
-          }
-
-          function deprecated (attr) {
-            if (typeof console !== 'undefined' && ChartJs.getOptions().env !== 'test') {
-              var warn = typeof console.warn === 'function' ? console.warn : console.log;
-              if (!! scope[attr]) {
-                warn.call(console, '"%s" is deprecated and will be removed in a future version. ' +
-                  'Please use "chart-%s" instead.', attr, attr);
-              }
-            }
+          function watchType (newVal, oldVal) {
+            if (isEmpty(newVal)) return;
+            if (angular.equals(newVal, oldVal)) return;
+            createChart(newVal, scope, elem);
           }
         }
       };
     };
 
+    function createChart (type, scope, elem) {
+      var options = getChartOptions(type, scope);
+      if (! hasData(scope) || ! canDisplay(type, scope, elem, options)) return;
+
+      var cvs = elem[0];
+      var ctx = cvs.getContext('2d');
+
+      scope.chartGetColor = getChartColorFn(scope);
+      var data = getChartData(type, scope);
+
+      // Destroy old chart if it exists to avoid ghost charts issue
+      // https://github.com/jtblin/angular-chart.js/issues/187
+      destroyChart(scope);
+
+      scope.chart = new ChartJs.Chart(ctx, {
+        type: type,
+        data: data,
+        options: options
+      });
+      scope.$emit('chart-create', scope.chart);
+      bindEvents(cvs, scope);
+    }
+
     function canUpdateChart (newVal, oldVal) {
       if (newVal && oldVal && newVal.length && oldVal.length) {
         return Array.isArray(newVal[0]) ?
@@ -231,56 +206,54 @@
       return carry + val;
     }
 
-    function getEventHandler (scope, chart, action, triggerOnlyOnChange) {
+    function getEventHandler (scope, action, triggerOnlyOnChange) {
       var lastState = null;
       return function (evt) {
-        var atEvent = chart.getPointsAtEvent || chart.getBarsAtEvent || chart.getSegmentsAtEvent;
+        var atEvent = scope.chart.getElementsAtEvent || scope.chart.getPointsAtEvent;
         if (atEvent) {
-          var activePoints = atEvent.call(chart, evt);
+          var activePoints = atEvent.call(scope.chart, evt);
           if (triggerOnlyOnChange === false || angular.equals(lastState, activePoints) === false) {
             lastState = activePoints;
             scope[action](activePoints, evt);
-            scope.$apply();
           }
         }
       };
     }
 
-    function getColours (type, scope) {
-      var notEnoughColours = false;
-      var colours = angular.copy(scope.colours ||
-        ChartJs.getOptions(type).colours ||
-        Chart.defaults.global.colours
+    function getColors (type, scope) {
+      var colors = angular.copy(scope.chartColors ||
+        ChartJs.getOptions(type).chartColors ||
+        Chart.defaults.global.colors
       );
-      while (colours.length < scope.data.length) {
-        colours.push(scope.getColour());
-        notEnoughColours = true;
+      var notEnoughColors = colors.length < scope.chartData.length;
+      while (colors.length < scope.chartData.length) {
+        colors.push(scope.chartGetColor());
       }
-      // mutate colours in this case as we don't want
-      // the colours to change on each refresh
-      if (notEnoughColours) scope.colours = colours;
-      return colours.map(convertColour);
+      // mutate colors in this case as we don't want
+      // the colors to change on each refresh
+      if (notEnoughColors) scope.chartColors = colors;
+      return colors.map(convertColor);
     }
 
-    function convertColour (colour) {
-      if (typeof colour === 'object' && colour !== null) return colour;
-      if (typeof colour === 'string' && colour[0] === '#') return getColour(hexToRgb(colour.substr(1)));
-      return getRandomColour();
+    function convertColor (color) {
+      if (typeof color === 'object' && color !== null) return color;
+      if (typeof color === 'string' && color[0] === '#') return getColor(hexToRgb(color.substr(1)));
+      return getRandomColor();
     }
 
-    function getRandomColour () {
-      var colour = [getRandomInt(0, 255), getRandomInt(0, 255), getRandomInt(0, 255)];
-      return getColour(colour);
+    function getRandomColor () {
+      var color = [getRandomInt(0, 255), getRandomInt(0, 255), getRandomInt(0, 255)];
+      return getColor(color);
     }
 
-    function getColour (colour) {
+    function getColor (color) {
       return {
-        fillColor: rgba(colour, 0.2),
-        strokeColor: rgba(colour, 1),
-        pointColor: rgba(colour, 1),
-        pointStrokeColor: '#fff',
-        pointHighlightFill: '#fff',
-        pointHighlightStroke: rgba(colour, 0.8)
+        backgroundColor: rgba(color, 0.2),
+        pointBackgroundColor: rgba(color, 1),
+        pointHoverBackgroundColor: rgba(color, 0.8),
+        borderColor: rgba(color, 1),
+        pointBorderColor: '#fff',
+        pointHoverBorderColor: rgba(color, 1)
       };
     }
 
@@ -288,13 +261,9 @@
       return Math.floor(Math.random() * (max - min + 1)) + min;
     }
 
-    function rgba (colour, alpha) {
-      if (usingExcanvas) {
-        // rgba not supported by IE8
-        return 'rgb(' + colour.join(',') + ')';
-      } else {
-        return 'rgba(' + colour.concat(alpha).join(',') + ')';
-      }
+    function rgba (color, alpha) {
+      // rgba not supported by IE8
+      return useExcanvas ? 'rgb(' + color.join(',') + ')' : 'rgba(' + color.concat(alpha).join(',') + ')';
     }
 
     // Credit: http://stackoverflow.com/a/11508164/1190235
@@ -307,52 +276,76 @@
       return [r, g, b];
     }
 
-    function getDataSets (labels, data, series, colours) {
+    function hasData (scope) {
+      return scope.chartData && scope.chartData.length;
+    }
+
+    function getChartColorFn (scope) {
+      return typeof scope.chartGetColor === 'function' ? scope.chartGetColor : getRandomColor;
+    }
+
+    function getChartData (type, scope) {
+      var colors = getColors(type, scope);
+      return Array.isArray(scope.chartData[0]) ?
+        getDataSets(scope.chartLabels, scope.chartData, scope.chartSeries || [], colors, scope.chartDatasetOverride) :
+        getData(scope.chartLabels, scope.chartData, colors, scope.chartDatasetOverride);
+    }
+
+    function getDataSets (labels, data, series, colors, datasetOverride) {
       return {
         labels: labels,
         datasets: data.map(function (item, i) {
-          return angular.extend({}, colours[i], {
+          var dataset = angular.extend({}, colors[i], {
             label: series[i],
             data: item
           });
+          if (datasetOverride && datasetOverride.length >= i) {
+            angular.merge(dataset, datasetOverride[i]);
+          }
+          return dataset;
         })
       };
     }
 
-    function getData (labels, data, colours) {
-      return labels.map(function (label, i) {
-        return angular.extend({}, colours[i], {
-          label: label,
-          value: data[i],
-          color: colours[i].strokeColor,
-          highlight: colours[i].pointHighlightStroke
-        });
-      });
+    function getData (labels, data, colors, datasetOverride) {
+      var dataset = {
+        labels: labels,
+        datasets: [{
+          data: data,
+          backgroundColor: colors.map(function (color) {
+            return color.pointBackgroundColor;
+          }),
+          hoverBackgroundColor: colors.map(function (color) {
+            return color.backgroundColor;
+          })
+        }]
+      };
+      if (datasetOverride) {
+        angular.merge(dataset.datasets[0], datasetOverride);
+      }
+      return dataset;
     }
 
-    function setLegend (elem, chart) {
-      var $parent = elem.parent(),
-          $oldLegend = $parent.find('chart-legend'),
-          legend = '<chart-legend>' + chart.generateLegend() + '</chart-legend>';
-      if ($oldLegend.length) $oldLegend.replaceWith(legend);
-      else $parent.append(legend);
+    function getChartOptions (type, scope) {
+      return angular.extend({}, ChartJs.getOptions(type), scope.chartOptions);
     }
 
-    function updateChart (chart, values, scope, elem) {
-      if (Array.isArray(scope.data[0])) {
-        chart.datasets.forEach(function (dataset, i) {
-          (dataset.points || dataset.bars).forEach(function (dataItem, j) {
-            dataItem.value = values[i][j];
-          });
+    function bindEvents (cvs, scope) {
+      cvs.onclick = scope.chartClick ? getEventHandler(scope, 'chartClick', false) : angular.noop;
+      cvs.onmousemove = scope.chartHover ? getEventHandler(scope, 'chartHover', true) : angular.noop;
+    }
+
+    function updateChart (values, scope) {
+      if (Array.isArray(scope.chartData[0])) {
+        scope.chart.data.datasets.forEach(function (dataset, i) {
+          dataset.data = values[i];
         });
       } else {
-        chart.segments.forEach(function (segment, i) {
-          segment.value = values[i];
-        });
+        scope.chart.data.datasets[0].data = values;
       }
-      chart.update();
-      scope.$emit('update', chart);
-      if (scope.legend && scope.legend !== 'false') setLegend(elem, chart);
+
+      scope.chart.update();
+      scope.$emit('chart-update', scope.chart);
     }
 
     function isEmpty (value) {
@@ -361,15 +354,21 @@
         (typeof value === 'object' && ! Object.keys(value).length);
     }
 
-    function isResponsive (type, scope) {
-      var options = angular.extend({}, Chart.defaults.global, ChartJs.getOptions(type), scope.options);
-      return options.responsive;
+    function canDisplay (type, scope, elem, options) {
+      // TODO: check parent?
+      if (options.responsive && elem[0].clientHeight === 0) {
+        $timeout(function () {
+          createChart(type, scope, elem);
+        }, 50, false);
+        return false;
+      }
+      return true;
     }
 
-    function destroyChart(chart, scope) {
-      if(! chart) return;
-      chart.destroy();
-      scope.$emit('destroy', chart);
+    function destroyChart(scope) {
+      if(! scope.chart) return;
+      scope.chart.destroy();
+      scope.$emit('chart-destroy', scope.chart);
     }
   }
 }));