[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/amd/src/ -> chartjs-lazy.js (source)

   1  /*!

   2   * Chart.js

   3   * http://chartjs.org/

   4   * Version: 2.1.6

   5   *

   6   * Copyright 2016 Nick Downie

   7   * Released under the MIT license

   8   * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md

   9   */
  10  
  11  /**

  12   * Description of import into Moodle:

  13   *

  14   * - Download from http://www.chartjs.org/docs/#getting-started-download-chart-js.

  15   * - Copy Chart.js to lib/amd/src/chartjs.js.

  16   * - Add these instructions to the file.

  17   * - Add the jshint ignore rules.

  18   */
  19  
  20  (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  21  
  22  },{}],2:[function(require,module,exports){
  23  /* MIT license */

  24  var colorNames = require(6);
  25  
  26  module.exports = {
  27     getRgba: getRgba,
  28     getHsla: getHsla,
  29     getRgb: getRgb,
  30     getHsl: getHsl,
  31     getHwb: getHwb,
  32     getAlpha: getAlpha,
  33  
  34     hexString: hexString,
  35     rgbString: rgbString,
  36     rgbaString: rgbaString,
  37     percentString: percentString,
  38     percentaString: percentaString,
  39     hslString: hslString,
  40     hslaString: hslaString,
  41     hwbString: hwbString,
  42     keyword: keyword
  43  }
  44  
  45  function getRgba(string) {
  46     if (!string) {
  47        return;
  48     }
  49     var abbr =  /^#([a-fA-F0-9]{3})$/,
  50         hex =  /^#([a-fA-F0-9]{6})$/,
  51         rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
  52         per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
  53         keyword = /(\w+)/;
  54  
  55     var rgb = [0, 0, 0],
  56         a = 1,
  57         match = string.match(abbr);
  58     if (match) {
  59        match = match[1];
  60        for (var i = 0; i < rgb.length; i++) {
  61           rgb[i] = parseInt(match[i] + match[i], 16);
  62        }
  63     }
  64     else if (match = string.match(hex)) {
  65        match = match[1];
  66        for (var i = 0; i < rgb.length; i++) {
  67           rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
  68        }
  69     }
  70     else if (match = string.match(rgba)) {
  71        for (var i = 0; i < rgb.length; i++) {
  72           rgb[i] = parseInt(match[i + 1]);
  73        }
  74        a = parseFloat(match[4]);
  75     }
  76     else if (match = string.match(per)) {
  77        for (var i = 0; i < rgb.length; i++) {
  78           rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
  79        }
  80        a = parseFloat(match[4]);
  81     }
  82     else if (match = string.match(keyword)) {
  83        if (match[1] == "transparent") {
  84           return [0, 0, 0, 0];
  85        }
  86        rgb = colorNames[match[1]];
  87        if (!rgb) {
  88           return;
  89        }
  90     }
  91  
  92     for (var i = 0; i < rgb.length; i++) {
  93        rgb[i] = scale(rgb[i], 0, 255);
  94     }
  95     if (!a && a != 0) {
  96        a = 1;
  97     }
  98     else {
  99        a = scale(a, 0, 1);
 100     }
 101     rgb[3] = a;
 102     return rgb;
 103  }
 104  
 105  function getHsla(string) {
 106     if (!string) {
 107        return;
 108     }
 109     var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
 110     var match = string.match(hsl);
 111     if (match) {
 112        var alpha = parseFloat(match[4]);
 113        var h = scale(parseInt(match[1]), 0, 360),
 114            s = scale(parseFloat(match[2]), 0, 100),
 115            l = scale(parseFloat(match[3]), 0, 100),
 116            a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
 117        return [h, s, l, a];
 118     }
 119  }
 120  
 121  function getHwb(string) {
 122     if (!string) {
 123        return;
 124     }
 125     var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
 126     var match = string.match(hwb);
 127     if (match) {
 128      var alpha = parseFloat(match[4]);
 129        var h = scale(parseInt(match[1]), 0, 360),
 130            w = scale(parseFloat(match[2]), 0, 100),
 131            b = scale(parseFloat(match[3]), 0, 100),
 132            a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
 133        return [h, w, b, a];
 134     }
 135  }
 136  
 137  function getRgb(string) {
 138     var rgba = getRgba(string);
 139     return rgba && rgba.slice(0, 3);
 140  }
 141  
 142  function getHsl(string) {
 143    var hsla = getHsla(string);
 144    return hsla && hsla.slice(0, 3);
 145  }
 146  
 147  function getAlpha(string) {
 148     var vals = getRgba(string);
 149     if (vals) {
 150        return vals[3];
 151     }
 152     else if (vals = getHsla(string)) {
 153        return vals[3];
 154     }
 155     else if (vals = getHwb(string)) {
 156        return vals[3];
 157     }
 158  }
 159  
 160  // generators

 161  function hexString(rgb) {
 162     return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
 163                + hexDouble(rgb[2]);
 164  }
 165  
 166  function rgbString(rgba, alpha) {
 167     if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
 168        return rgbaString(rgba, alpha);
 169     }
 170     return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
 171  }
 172  
 173  function rgbaString(rgba, alpha) {
 174     if (alpha === undefined) {
 175        alpha = (rgba[3] !== undefined ? rgba[3] : 1);
 176     }
 177     return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
 178             + ", " + alpha + ")";
 179  }
 180  
 181  function percentString(rgba, alpha) {
 182     if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
 183        return percentaString(rgba, alpha);
 184     }
 185     var r = Math.round(rgba[0]/255 * 100),
 186         g = Math.round(rgba[1]/255 * 100),
 187         b = Math.round(rgba[2]/255 * 100);
 188  
 189     return "rgb(" + r + "%, " + g + "%, " + b + "%)";
 190  }
 191  
 192  function percentaString(rgba, alpha) {
 193     var r = Math.round(rgba[0]/255 * 100),
 194         g = Math.round(rgba[1]/255 * 100),
 195         b = Math.round(rgba[2]/255 * 100);
 196     return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
 197  }
 198  
 199  function hslString(hsla, alpha) {
 200     if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
 201        return hslaString(hsla, alpha);
 202     }
 203     return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
 204  }
 205  
 206  function hslaString(hsla, alpha) {
 207     if (alpha === undefined) {
 208        alpha = (hsla[3] !== undefined ? hsla[3] : 1);
 209     }
 210     return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
 211             + alpha + ")";
 212  }
 213  
 214  // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax

 215  // (hwb have alpha optional & 1 is default value)

 216  function hwbString(hwb, alpha) {
 217     if (alpha === undefined) {
 218        alpha = (hwb[3] !== undefined ? hwb[3] : 1);
 219     }
 220     return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
 221             + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
 222  }
 223  
 224  function keyword(rgb) {
 225    return reverseNames[rgb.slice(0, 3)];
 226  }
 227  
 228  // helpers

 229  function scale(num, min, max) {
 230     return Math.min(Math.max(min, num), max);
 231  }
 232  
 233  function hexDouble(num) {
 234    var str = num.toString(16).toUpperCase();
 235    return (str.length < 2) ? "0" + str : str;
 236  }
 237  
 238  
 239  //create a list of reverse color names

 240  var reverseNames = {};
 241  for (var name in colorNames) {
 242     reverseNames[colorNames[name]] = name;
 243  }
 244  
 245  },{"6":6}],3:[function(require,module,exports){
 246  /* MIT license */

 247  var convert = require(5);
 248  var string = require(2);
 249  
 250  var Color = function (obj) {
 251      if (obj instanceof Color) {
 252          return obj;
 253      }
 254      if (!(this instanceof Color)) {
 255          return new Color(obj);
 256      }
 257  
 258      this.values = {
 259          rgb: [0, 0, 0],
 260          hsl: [0, 0, 0],
 261          hsv: [0, 0, 0],
 262          hwb: [0, 0, 0],
 263          cmyk: [0, 0, 0, 0],
 264          alpha: 1
 265      };
 266  
 267      // parse Color() argument

 268      var vals;
 269      if (typeof obj === 'string') {
 270          vals = string.getRgba(obj);
 271          if (vals) {
 272              this.setValues('rgb', vals);
 273          } else if (vals = string.getHsla(obj)) {
 274              this.setValues('hsl', vals);
 275          } else if (vals = string.getHwb(obj)) {
 276              this.setValues('hwb', vals);
 277          } else {
 278              throw new Error('Unable to parse color from string "' + obj + '"');
 279          }
 280      } else if (typeof obj === 'object') {
 281          vals = obj;
 282          if (vals.r !== undefined || vals.red !== undefined) {
 283              this.setValues('rgb', vals);
 284          } else if (vals.l !== undefined || vals.lightness !== undefined) {
 285              this.setValues('hsl', vals);
 286          } else if (vals.v !== undefined || vals.value !== undefined) {
 287              this.setValues('hsv', vals);
 288          } else if (vals.w !== undefined || vals.whiteness !== undefined) {
 289              this.setValues('hwb', vals);
 290          } else if (vals.c !== undefined || vals.cyan !== undefined) {
 291              this.setValues('cmyk', vals);
 292          } else {
 293              throw new Error('Unable to parse color from object ' + JSON.stringify(obj));
 294          }
 295      }
 296  };
 297  
 298  Color.prototype = {
 299      rgb: function () {
 300          return this.setSpace('rgb', arguments);
 301      },
 302      hsl: function () {
 303          return this.setSpace('hsl', arguments);
 304      },
 305      hsv: function () {
 306          return this.setSpace('hsv', arguments);
 307      },
 308      hwb: function () {
 309          return this.setSpace('hwb', arguments);
 310      },
 311      cmyk: function () {
 312          return this.setSpace('cmyk', arguments);
 313      },
 314  
 315      rgbArray: function () {
 316          return this.values.rgb;
 317      },
 318      hslArray: function () {
 319          return this.values.hsl;
 320      },
 321      hsvArray: function () {
 322          return this.values.hsv;
 323      },
 324      hwbArray: function () {
 325          var values = this.values;
 326          if (values.alpha !== 1) {
 327              return values.hwb.concat([values.alpha]);
 328          }
 329          return values.hwb;
 330      },
 331      cmykArray: function () {
 332          return this.values.cmyk;
 333      },
 334      rgbaArray: function () {
 335          var values = this.values;
 336          return values.rgb.concat([values.alpha]);
 337      },
 338      hslaArray: function () {
 339          var values = this.values;
 340          return values.hsl.concat([values.alpha]);
 341      },
 342      alpha: function (val) {
 343          if (val === undefined) {
 344              return this.values.alpha;
 345          }
 346          this.setValues('alpha', val);
 347          return this;
 348      },
 349  
 350      red: function (val) {
 351          return this.setChannel('rgb', 0, val);
 352      },
 353      green: function (val) {
 354          return this.setChannel('rgb', 1, val);
 355      },
 356      blue: function (val) {
 357          return this.setChannel('rgb', 2, val);
 358      },
 359      hue: function (val) {
 360          if (val) {
 361              val %= 360;
 362              val = val < 0 ? 360 + val : val;
 363          }
 364          return this.setChannel('hsl', 0, val);
 365      },
 366      saturation: function (val) {
 367          return this.setChannel('hsl', 1, val);
 368      },
 369      lightness: function (val) {
 370          return this.setChannel('hsl', 2, val);
 371      },
 372      saturationv: function (val) {
 373          return this.setChannel('hsv', 1, val);
 374      },
 375      whiteness: function (val) {
 376          return this.setChannel('hwb', 1, val);
 377      },
 378      blackness: function (val) {
 379          return this.setChannel('hwb', 2, val);
 380      },
 381      value: function (val) {
 382          return this.setChannel('hsv', 2, val);
 383      },
 384      cyan: function (val) {
 385          return this.setChannel('cmyk', 0, val);
 386      },
 387      magenta: function (val) {
 388          return this.setChannel('cmyk', 1, val);
 389      },
 390      yellow: function (val) {
 391          return this.setChannel('cmyk', 2, val);
 392      },
 393      black: function (val) {
 394          return this.setChannel('cmyk', 3, val);
 395      },
 396  
 397      hexString: function () {
 398          return string.hexString(this.values.rgb);
 399      },
 400      rgbString: function () {
 401          return string.rgbString(this.values.rgb, this.values.alpha);
 402      },
 403      rgbaString: function () {
 404          return string.rgbaString(this.values.rgb, this.values.alpha);
 405      },
 406      percentString: function () {
 407          return string.percentString(this.values.rgb, this.values.alpha);
 408      },
 409      hslString: function () {
 410          return string.hslString(this.values.hsl, this.values.alpha);
 411      },
 412      hslaString: function () {
 413          return string.hslaString(this.values.hsl, this.values.alpha);
 414      },
 415      hwbString: function () {
 416          return string.hwbString(this.values.hwb, this.values.alpha);
 417      },
 418      keyword: function () {
 419          return string.keyword(this.values.rgb, this.values.alpha);
 420      },
 421  
 422      rgbNumber: function () {
 423          var rgb = this.values.rgb;
 424          return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
 425      },
 426  
 427      luminosity: function () {
 428          // http://www.w3.org/TR/WCAG20/#relativeluminancedef

 429          var rgb = this.values.rgb;
 430          var lum = [];
 431          for (var i = 0; i < rgb.length; i++) {
 432              var chan = rgb[i] / 255;
 433              lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
 434          }
 435          return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
 436      },
 437  
 438      contrast: function (color2) {
 439          // http://www.w3.org/TR/WCAG20/#contrast-ratiodef

 440          var lum1 = this.luminosity();
 441          var lum2 = color2.luminosity();
 442          if (lum1 > lum2) {
 443              return (lum1 + 0.05) / (lum2 + 0.05);
 444          }
 445          return (lum2 + 0.05) / (lum1 + 0.05);
 446      },
 447  
 448      level: function (color2) {
 449          var contrastRatio = this.contrast(color2);
 450          if (contrastRatio >= 7.1) {
 451              return 'AAA';
 452          }
 453  
 454          return (contrastRatio >= 4.5) ? 'AA' : '';
 455      },
 456  
 457      dark: function () {
 458          // YIQ equation from http://24ways.org/2010/calculating-color-contrast

 459          var rgb = this.values.rgb;
 460          var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
 461          return yiq < 128;
 462      },
 463  
 464      light: function () {
 465          return !this.dark();
 466      },
 467  
 468      negate: function () {
 469          var rgb = [];
 470          for (var i = 0; i < 3; i++) {
 471              rgb[i] = 255 - this.values.rgb[i];
 472          }
 473          this.setValues('rgb', rgb);
 474          return this;
 475      },
 476  
 477      lighten: function (ratio) {
 478          var hsl = this.values.hsl;
 479          hsl[2] += hsl[2] * ratio;
 480          this.setValues('hsl', hsl);
 481          return this;
 482      },
 483  
 484      darken: function (ratio) {
 485          var hsl = this.values.hsl;
 486          hsl[2] -= hsl[2] * ratio;
 487          this.setValues('hsl', hsl);
 488          return this;
 489      },
 490  
 491      saturate: function (ratio) {
 492          var hsl = this.values.hsl;
 493          hsl[1] += hsl[1] * ratio;
 494          this.setValues('hsl', hsl);
 495          return this;
 496      },
 497  
 498      desaturate: function (ratio) {
 499          var hsl = this.values.hsl;
 500          hsl[1] -= hsl[1] * ratio;
 501          this.setValues('hsl', hsl);
 502          return this;
 503      },
 504  
 505      whiten: function (ratio) {
 506          var hwb = this.values.hwb;
 507          hwb[1] += hwb[1] * ratio;
 508          this.setValues('hwb', hwb);
 509          return this;
 510      },
 511  
 512      blacken: function (ratio) {
 513          var hwb = this.values.hwb;
 514          hwb[2] += hwb[2] * ratio;
 515          this.setValues('hwb', hwb);
 516          return this;
 517      },
 518  
 519      greyscale: function () {
 520          var rgb = this.values.rgb;
 521          // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale

 522          var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
 523          this.setValues('rgb', [val, val, val]);
 524          return this;
 525      },
 526  
 527      clearer: function (ratio) {
 528          var alpha = this.values.alpha;
 529          this.setValues('alpha', alpha - (alpha * ratio));
 530          return this;
 531      },
 532  
 533      opaquer: function (ratio) {
 534          var alpha = this.values.alpha;
 535          this.setValues('alpha', alpha + (alpha * ratio));
 536          return this;
 537      },
 538  
 539      rotate: function (degrees) {
 540          var hsl = this.values.hsl;
 541          var hue = (hsl[0] + degrees) % 360;
 542          hsl[0] = hue < 0 ? 360 + hue : hue;
 543          this.setValues('hsl', hsl);
 544          return this;
 545      },
 546  
 547      /**

 548       * Ported from sass implementation in C

 549       * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209

 550       */
 551      mix: function (mixinColor, weight) {
 552          var color1 = this;
 553          var color2 = mixinColor;
 554          var p = weight === undefined ? 0.5 : weight;
 555  
 556          var w = 2 * p - 1;
 557          var a = color1.alpha() - color2.alpha();
 558  
 559          var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
 560          var w2 = 1 - w1;
 561  
 562          return this
 563              .rgb(
 564                  w1 * color1.red() + w2 * color2.red(),
 565                  w1 * color1.green() + w2 * color2.green(),
 566                  w1 * color1.blue() + w2 * color2.blue()
 567              )
 568              .alpha(color1.alpha() * p + color2.alpha() * (1 - p));
 569      },
 570  
 571      toJSON: function () {
 572          return this.rgb();
 573      },
 574  
 575      clone: function () {
 576          // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,

 577          // making the final build way to big to embed in Chart.js. So let's do it manually,

 578          // assuming that values to clone are 1 dimension arrays containing only numbers,

 579          // except 'alpha' which is a number.

 580          var result = new Color();
 581          var source = this.values;
 582          var target = result.values;
 583          var value, type;
 584  
 585          for (var prop in source) {
 586              if (source.hasOwnProperty(prop)) {
 587                  value = source[prop];
 588                  type = ({}).toString.call(value);
 589                  if (type === '[object Array]') {
 590                      target[prop] = value.slice(0);
 591                  } else if (type === '[object Number]') {
 592                      target[prop] = value;
 593                  } else {
 594                      console.error('unexpected color value:', value);
 595                  }
 596              }
 597          }
 598  
 599          return result;
 600      }
 601  };
 602  
 603  Color.prototype.spaces = {
 604      rgb: ['red', 'green', 'blue'],
 605      hsl: ['hue', 'saturation', 'lightness'],
 606      hsv: ['hue', 'saturation', 'value'],
 607      hwb: ['hue', 'whiteness', 'blackness'],
 608      cmyk: ['cyan', 'magenta', 'yellow', 'black']
 609  };
 610  
 611  Color.prototype.maxes = {
 612      rgb: [255, 255, 255],
 613      hsl: [360, 100, 100],
 614      hsv: [360, 100, 100],
 615      hwb: [360, 100, 100],
 616      cmyk: [100, 100, 100, 100]
 617  };
 618  
 619  Color.prototype.getValues = function (space) {
 620      var values = this.values;
 621      var vals = {};
 622  
 623      for (var i = 0; i < space.length; i++) {
 624          vals[space.charAt(i)] = values[space][i];
 625      }
 626  
 627      if (values.alpha !== 1) {
 628          vals.a = values.alpha;
 629      }
 630  
 631      // {r: 255, g: 255, b: 255, a: 0.4}

 632      return vals;
 633  };
 634  
 635  Color.prototype.setValues = function (space, vals) {
 636      var values = this.values;
 637      var spaces = this.spaces;
 638      var maxes = this.maxes;
 639      var alpha = 1;
 640      var i;
 641  
 642      if (space === 'alpha') {
 643          alpha = vals;
 644      } else if (vals.length) {
 645          // [10, 10, 10]

 646          values[space] = vals.slice(0, space.length);
 647          alpha = vals[space.length];
 648      } else if (vals[space.charAt(0)] !== undefined) {
 649          // {r: 10, g: 10, b: 10}

 650          for (i = 0; i < space.length; i++) {
 651              values[space][i] = vals[space.charAt(i)];
 652          }
 653  
 654          alpha = vals.a;
 655      } else if (vals[spaces[space][0]] !== undefined) {
 656          // {red: 10, green: 10, blue: 10}

 657          var chans = spaces[space];
 658  
 659          for (i = 0; i < space.length; i++) {
 660              values[space][i] = vals[chans[i]];
 661          }
 662  
 663          alpha = vals.alpha;
 664      }
 665  
 666      values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
 667  
 668      if (space === 'alpha') {
 669          return false;
 670      }
 671  
 672      var capped;
 673  
 674      // cap values of the space prior converting all values

 675      for (i = 0; i < space.length; i++) {
 676          capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
 677          values[space][i] = Math.round(capped);
 678      }
 679  
 680      // convert to all the other color spaces

 681      for (var sname in spaces) {
 682          if (sname !== space) {
 683              values[sname] = convert[space][sname](values[space]);
 684          }
 685      }
 686  
 687      return true;
 688  };
 689  
 690  Color.prototype.setSpace = function (space, args) {
 691      var vals = args[0];
 692  
 693      if (vals === undefined) {
 694          // color.rgb()

 695          return this.getValues(space);
 696      }
 697  
 698      // color.rgb(10, 10, 10)

 699      if (typeof vals === 'number') {
 700          vals = Array.prototype.slice.call(args);
 701      }
 702  
 703      this.setValues(space, vals);
 704      return this;
 705  };
 706  
 707  Color.prototype.setChannel = function (space, index, val) {
 708      var svalues = this.values[space];
 709      if (val === undefined) {
 710          // color.red()

 711          return svalues[index];
 712      } else if (val === svalues[index]) {
 713          // color.red(color.red())

 714          return this;
 715      }
 716  
 717      // color.red(100)

 718      svalues[index] = val;
 719      this.setValues(space, svalues);
 720  
 721      return this;
 722  };
 723  
 724  if (typeof window !== 'undefined') {
 725      window.Color = Color;
 726  }
 727  
 728  module.exports = Color;
 729  
 730  },{"2":2,"5":5}],4:[function(require,module,exports){
 731  /* MIT license */

 732  
 733  module.exports = {
 734    rgb2hsl: rgb2hsl,
 735    rgb2hsv: rgb2hsv,
 736    rgb2hwb: rgb2hwb,
 737    rgb2cmyk: rgb2cmyk,
 738    rgb2keyword: rgb2keyword,
 739    rgb2xyz: rgb2xyz,
 740    rgb2lab: rgb2lab,
 741    rgb2lch: rgb2lch,
 742  
 743    hsl2rgb: hsl2rgb,
 744    hsl2hsv: hsl2hsv,
 745    hsl2hwb: hsl2hwb,
 746    hsl2cmyk: hsl2cmyk,
 747    hsl2keyword: hsl2keyword,
 748  
 749    hsv2rgb: hsv2rgb,
 750    hsv2hsl: hsv2hsl,
 751    hsv2hwb: hsv2hwb,
 752    hsv2cmyk: hsv2cmyk,
 753    hsv2keyword: hsv2keyword,
 754  
 755    hwb2rgb: hwb2rgb,
 756    hwb2hsl: hwb2hsl,
 757    hwb2hsv: hwb2hsv,
 758    hwb2cmyk: hwb2cmyk,
 759    hwb2keyword: hwb2keyword,
 760  
 761    cmyk2rgb: cmyk2rgb,
 762    cmyk2hsl: cmyk2hsl,
 763    cmyk2hsv: cmyk2hsv,
 764    cmyk2hwb: cmyk2hwb,
 765    cmyk2keyword: cmyk2keyword,
 766  
 767    keyword2rgb: keyword2rgb,
 768    keyword2hsl: keyword2hsl,
 769    keyword2hsv: keyword2hsv,
 770    keyword2hwb: keyword2hwb,
 771    keyword2cmyk: keyword2cmyk,
 772    keyword2lab: keyword2lab,
 773    keyword2xyz: keyword2xyz,
 774  
 775    xyz2rgb: xyz2rgb,
 776    xyz2lab: xyz2lab,
 777    xyz2lch: xyz2lch,
 778  
 779    lab2xyz: lab2xyz,
 780    lab2rgb: lab2rgb,
 781    lab2lch: lab2lch,
 782  
 783    lch2lab: lch2lab,
 784    lch2xyz: lch2xyz,
 785    lch2rgb: lch2rgb
 786  }
 787  
 788  
 789  function rgb2hsl(rgb) {
 790    var r = rgb[0]/255,
 791        g = rgb[1]/255,
 792        b = rgb[2]/255,
 793        min = Math.min(r, g, b),
 794        max = Math.max(r, g, b),
 795        delta = max - min,
 796        h, s, l;
 797  
 798    if (max == min)
 799      h = 0;
 800    else if (r == max)
 801      h = (g - b) / delta;
 802    else if (g == max)
 803      h = 2 + (b - r) / delta;
 804    else if (b == max)
 805      h = 4 + (r - g)/ delta;
 806  
 807    h = Math.min(h * 60, 360);
 808  
 809    if (h < 0)
 810      h += 360;
 811  
 812    l = (min + max) / 2;
 813  
 814    if (max == min)
 815      s = 0;
 816    else if (l <= 0.5)
 817      s = delta / (max + min);
 818    else
 819      s = delta / (2 - max - min);
 820  
 821    return [h, s * 100, l * 100];
 822  }
 823  
 824  function rgb2hsv(rgb) {
 825    var r = rgb[0],
 826        g = rgb[1],
 827        b = rgb[2],
 828        min = Math.min(r, g, b),
 829        max = Math.max(r, g, b),
 830        delta = max - min,
 831        h, s, v;
 832  
 833    if (max == 0)
 834      s = 0;
 835    else
 836      s = (delta/max * 1000)/10;
 837  
 838    if (max == min)
 839      h = 0;
 840    else if (r == max)
 841      h = (g - b) / delta;
 842    else if (g == max)
 843      h = 2 + (b - r) / delta;
 844    else if (b == max)
 845      h = 4 + (r - g) / delta;
 846  
 847    h = Math.min(h * 60, 360);
 848  
 849    if (h < 0)
 850      h += 360;
 851  
 852    v = ((max / 255) * 1000) / 10;
 853  
 854    return [h, s, v];
 855  }
 856  
 857  function rgb2hwb(rgb) {
 858    var r = rgb[0],
 859        g = rgb[1],
 860        b = rgb[2],
 861        h = rgb2hsl(rgb)[0],
 862        w = 1/255 * Math.min(r, Math.min(g, b)),
 863        b = 1 - 1/255 * Math.max(r, Math.max(g, b));
 864  
 865    return [h, w * 100, b * 100];
 866  }
 867  
 868  function rgb2cmyk(rgb) {
 869    var r = rgb[0] / 255,
 870        g = rgb[1] / 255,
 871        b = rgb[2] / 255,
 872        c, m, y, k;
 873  
 874    k = Math.min(1 - r, 1 - g, 1 - b);
 875    c = (1 - r - k) / (1 - k) || 0;
 876    m = (1 - g - k) / (1 - k) || 0;
 877    y = (1 - b - k) / (1 - k) || 0;
 878    return [c * 100, m * 100, y * 100, k * 100];
 879  }
 880  
 881  function rgb2keyword(rgb) {
 882    return reverseKeywords[JSON.stringify(rgb)];
 883  }
 884  
 885  function rgb2xyz(rgb) {
 886    var r = rgb[0] / 255,
 887        g = rgb[1] / 255,
 888        b = rgb[2] / 255;
 889  
 890    // assume sRGB

 891    r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
 892    g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
 893    b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
 894  
 895    var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
 896    var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
 897    var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
 898  
 899    return [x * 100, y *100, z * 100];
 900  }
 901  
 902  function rgb2lab(rgb) {
 903    var xyz = rgb2xyz(rgb),
 904          x = xyz[0],
 905          y = xyz[1],
 906          z = xyz[2],
 907          l, a, b;
 908  
 909    x /= 95.047;
 910    y /= 100;
 911    z /= 108.883;
 912  
 913    x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
 914    y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
 915    z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
 916  
 917    l = (116 * y) - 16;
 918    a = 500 * (x - y);
 919    b = 200 * (y - z);
 920  
 921    return [l, a, b];
 922  }
 923  
 924  function rgb2lch(args) {
 925    return lab2lch(rgb2lab(args));
 926  }
 927  
 928  function hsl2rgb(hsl) {
 929    var h = hsl[0] / 360,
 930        s = hsl[1] / 100,
 931        l = hsl[2] / 100,
 932        t1, t2, t3, rgb, val;
 933  
 934    if (s == 0) {
 935      val = l * 255;
 936      return [val, val, val];
 937    }
 938  
 939    if (l < 0.5)
 940      t2 = l * (1 + s);
 941    else
 942      t2 = l + s - l * s;
 943    t1 = 2 * l - t2;
 944  
 945    rgb = [0, 0, 0];
 946    for (var i = 0; i < 3; i++) {
 947      t3 = h + 1 / 3 * - (i - 1);
 948      t3 < 0 && t3++;
 949      t3 > 1 && t3--;
 950  
 951      if (6 * t3 < 1)
 952        val = t1 + (t2 - t1) * 6 * t3;
 953      else if (2 * t3 < 1)
 954        val = t2;
 955      else if (3 * t3 < 2)
 956        val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
 957      else
 958        val = t1;
 959  
 960      rgb[i] = val * 255;
 961    }
 962  
 963    return rgb;
 964  }
 965  
 966  function hsl2hsv(hsl) {
 967    var h = hsl[0],
 968        s = hsl[1] / 100,
 969        l = hsl[2] / 100,
 970        sv, v;
 971  
 972    if(l === 0) {
 973        // no need to do calc on black

 974        // also avoids divide by 0 error

 975        return [0, 0, 0];
 976    }
 977  
 978    l *= 2;
 979    s *= (l <= 1) ? l : 2 - l;
 980    v = (l + s) / 2;
 981    sv = (2 * s) / (l + s);
 982    return [h, sv * 100, v * 100];
 983  }
 984  
 985  function hsl2hwb(args) {
 986    return rgb2hwb(hsl2rgb(args));
 987  }
 988  
 989  function hsl2cmyk(args) {
 990    return rgb2cmyk(hsl2rgb(args));
 991  }
 992  
 993  function hsl2keyword(args) {
 994    return rgb2keyword(hsl2rgb(args));
 995  }
 996  
 997  
 998  function hsv2rgb(hsv) {
 999    var h = hsv[0] / 60,
1000        s = hsv[1] / 100,
1001        v = hsv[2] / 100,
1002        hi = Math.floor(h) % 6;
1003  
1004    var f = h - Math.floor(h),
1005        p = 255 * v * (1 - s),
1006        q = 255 * v * (1 - (s * f)),
1007        t = 255 * v * (1 - (s * (1 - f))),
1008        v = 255 * v;
1009  
1010    switch(hi) {
1011      case 0:
1012        return [v, t, p];
1013      case 1:
1014        return [q, v, p];
1015      case 2:
1016        return [p, v, t];
1017      case 3:
1018        return [p, q, v];
1019      case 4:
1020        return [t, p, v];
1021      case 5:
1022        return [v, p, q];
1023    }
1024  }
1025  
1026  function hsv2hsl(hsv) {
1027    var h = hsv[0],
1028        s = hsv[1] / 100,
1029        v = hsv[2] / 100,
1030        sl, l;
1031  
1032    l = (2 - s) * v;
1033    sl = s * v;
1034    sl /= (l <= 1) ? l : 2 - l;
1035    sl = sl || 0;
1036    l /= 2;
1037    return [h, sl * 100, l * 100];
1038  }
1039  
1040  function hsv2hwb(args) {
1041    return rgb2hwb(hsv2rgb(args))
1042  }
1043  
1044  function hsv2cmyk(args) {
1045    return rgb2cmyk(hsv2rgb(args));
1046  }
1047  
1048  function hsv2keyword(args) {
1049    return rgb2keyword(hsv2rgb(args));
1050  }
1051  
1052  // http://dev.w3.org/csswg/css-color/#hwb-to-rgb

1053  function hwb2rgb(hwb) {
1054    var h = hwb[0] / 360,
1055        wh = hwb[1] / 100,
1056        bl = hwb[2] / 100,
1057        ratio = wh + bl,
1058        i, v, f, n;
1059  
1060    // wh + bl cant be > 1

1061    if (ratio > 1) {
1062      wh /= ratio;
1063      bl /= ratio;
1064    }
1065  
1066    i = Math.floor(6 * h);
1067    v = 1 - bl;
1068    f = 6 * h - i;
1069    if ((i & 0x01) != 0) {
1070      f = 1 - f;
1071    }
1072    n = wh + f * (v - wh);  // linear interpolation

1073  
1074    switch (i) {
1075      default:
1076      case 6:
1077      case 0: r = v; g = n; b = wh; break;
1078      case 1: r = n; g = v; b = wh; break;
1079      case 2: r = wh; g = v; b = n; break;
1080      case 3: r = wh; g = n; b = v; break;
1081      case 4: r = n; g = wh; b = v; break;
1082      case 5: r = v; g = wh; b = n; break;
1083    }
1084  
1085    return [r * 255, g * 255, b * 255];
1086  }
1087  
1088  function hwb2hsl(args) {
1089    return rgb2hsl(hwb2rgb(args));
1090  }
1091  
1092  function hwb2hsv(args) {
1093    return rgb2hsv(hwb2rgb(args));
1094  }
1095  
1096  function hwb2cmyk(args) {
1097    return rgb2cmyk(hwb2rgb(args));
1098  }
1099  
1100  function hwb2keyword(args) {
1101    return rgb2keyword(hwb2rgb(args));
1102  }
1103  
1104  function cmyk2rgb(cmyk) {
1105    var c = cmyk[0] / 100,
1106        m = cmyk[1] / 100,
1107        y = cmyk[2] / 100,
1108        k = cmyk[3] / 100,
1109        r, g, b;
1110  
1111    r = 1 - Math.min(1, c * (1 - k) + k);
1112    g = 1 - Math.min(1, m * (1 - k) + k);
1113    b = 1 - Math.min(1, y * (1 - k) + k);
1114    return [r * 255, g * 255, b * 255];
1115  }
1116  
1117  function cmyk2hsl(args) {
1118    return rgb2hsl(cmyk2rgb(args));
1119  }
1120  
1121  function cmyk2hsv(args) {
1122    return rgb2hsv(cmyk2rgb(args));
1123  }
1124  
1125  function cmyk2hwb(args) {
1126    return rgb2hwb(cmyk2rgb(args));
1127  }
1128  
1129  function cmyk2keyword(args) {
1130    return rgb2keyword(cmyk2rgb(args));
1131  }
1132  
1133  
1134  function xyz2rgb(xyz) {
1135    var x = xyz[0] / 100,
1136        y = xyz[1] / 100,
1137        z = xyz[2] / 100,
1138        r, g, b;
1139  
1140    r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
1141    g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
1142    b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
1143  
1144    // assume sRGB

1145    r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
1146      : r = (r * 12.92);
1147  
1148    g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
1149      : g = (g * 12.92);
1150  
1151    b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
1152      : b = (b * 12.92);
1153  
1154    r = Math.min(Math.max(0, r), 1);
1155    g = Math.min(Math.max(0, g), 1);
1156    b = Math.min(Math.max(0, b), 1);
1157  
1158    return [r * 255, g * 255, b * 255];
1159  }
1160  
1161  function xyz2lab(xyz) {
1162    var x = xyz[0],
1163        y = xyz[1],
1164        z = xyz[2],
1165        l, a, b;
1166  
1167    x /= 95.047;
1168    y /= 100;
1169    z /= 108.883;
1170  
1171    x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
1172    y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
1173    z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
1174  
1175    l = (116 * y) - 16;
1176    a = 500 * (x - y);
1177    b = 200 * (y - z);
1178  
1179    return [l, a, b];
1180  }
1181  
1182  function xyz2lch(args) {
1183    return lab2lch(xyz2lab(args));
1184  }
1185  
1186  function lab2xyz(lab) {
1187    var l = lab[0],
1188        a = lab[1],
1189        b = lab[2],
1190        x, y, z, y2;
1191  
1192    if (l <= 8) {
1193      y = (l * 100) / 903.3;
1194      y2 = (7.787 * (y / 100)) + (16 / 116);
1195    } else {
1196      y = 100 * Math.pow((l + 16) / 116, 3);
1197      y2 = Math.pow(y / 100, 1/3);
1198    }
1199  
1200    x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
1201  
1202    z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
1203  
1204    return [x, y, z];
1205  }
1206  
1207  function lab2lch(lab) {
1208    var l = lab[0],
1209        a = lab[1],
1210        b = lab[2],
1211        hr, h, c;
1212  
1213    hr = Math.atan2(b, a);
1214    h = hr * 360 / 2 / Math.PI;
1215    if (h < 0) {
1216      h += 360;
1217    }
1218    c = Math.sqrt(a * a + b * b);
1219    return [l, c, h];
1220  }
1221  
1222  function lab2rgb(args) {
1223    return xyz2rgb(lab2xyz(args));
1224  }
1225  
1226  function lch2lab(lch) {
1227    var l = lch[0],
1228        c = lch[1],
1229        h = lch[2],
1230        a, b, hr;
1231  
1232    hr = h / 360 * 2 * Math.PI;
1233    a = c * Math.cos(hr);
1234    b = c * Math.sin(hr);
1235    return [l, a, b];
1236  }
1237  
1238  function lch2xyz(args) {
1239    return lab2xyz(lch2lab(args));
1240  }
1241  
1242  function lch2rgb(args) {
1243    return lab2rgb(lch2lab(args));
1244  }
1245  
1246  function keyword2rgb(keyword) {
1247    return cssKeywords[keyword];
1248  }
1249  
1250  function keyword2hsl(args) {
1251    return rgb2hsl(keyword2rgb(args));
1252  }
1253  
1254  function keyword2hsv(args) {
1255    return rgb2hsv(keyword2rgb(args));
1256  }
1257  
1258  function keyword2hwb(args) {
1259    return rgb2hwb(keyword2rgb(args));
1260  }
1261  
1262  function keyword2cmyk(args) {
1263    return rgb2cmyk(keyword2rgb(args));
1264  }
1265  
1266  function keyword2lab(args) {
1267    return rgb2lab(keyword2rgb(args));
1268  }
1269  
1270  function keyword2xyz(args) {
1271    return rgb2xyz(keyword2rgb(args));
1272  }
1273  
1274  var cssKeywords = {
1275    aliceblue:  [240,248,255],
1276    antiquewhite: [250,235,215],
1277    aqua: [0,255,255],
1278    aquamarine: [127,255,212],
1279    azure:  [240,255,255],
1280    beige:  [245,245,220],
1281    bisque: [255,228,196],
1282    black:  [0,0,0],
1283    blanchedalmond: [255,235,205],
1284    blue: [0,0,255],
1285    blueviolet: [138,43,226],
1286    brown:  [165,42,42],
1287    burlywood:  [222,184,135],
1288    cadetblue:  [95,158,160],
1289    chartreuse: [127,255,0],
1290    chocolate:  [210,105,30],
1291    coral:  [255,127,80],
1292    cornflowerblue: [100,149,237],
1293    cornsilk: [255,248,220],
1294    crimson:  [220,20,60],
1295    cyan: [0,255,255],
1296    darkblue: [0,0,139],
1297    darkcyan: [0,139,139],
1298    darkgoldenrod:  [184,134,11],
1299    darkgray: [169,169,169],
1300    darkgreen:  [0,100,0],
1301    darkgrey: [169,169,169],
1302    darkkhaki:  [189,183,107],
1303    darkmagenta:  [139,0,139],
1304    darkolivegreen: [85,107,47],
1305    darkorange: [255,140,0],
1306    darkorchid: [153,50,204],
1307    darkred:  [139,0,0],
1308    darksalmon: [233,150,122],
1309    darkseagreen: [143,188,143],
1310    darkslateblue:  [72,61,139],
1311    darkslategray:  [47,79,79],
1312    darkslategrey:  [47,79,79],
1313    darkturquoise:  [0,206,209],
1314    darkviolet: [148,0,211],
1315    deeppink: [255,20,147],
1316    deepskyblue:  [0,191,255],
1317    dimgray:  [105,105,105],
1318    dimgrey:  [105,105,105],
1319    dodgerblue: [30,144,255],
1320    firebrick:  [178,34,34],
1321    floralwhite:  [255,250,240],
1322    forestgreen:  [34,139,34],
1323    fuchsia:  [255,0,255],
1324    gainsboro:  [220,220,220],
1325    ghostwhite: [248,248,255],
1326    gold: [255,215,0],
1327    goldenrod:  [218,165,32],
1328    gray: [128,128,128],
1329    green:  [0,128,0],
1330    greenyellow:  [173,255,47],
1331    grey: [128,128,128],
1332    honeydew: [240,255,240],
1333    hotpink:  [255,105,180],
1334    indianred:  [205,92,92],
1335    indigo: [75,0,130],
1336    ivory:  [255,255,240],
1337    khaki:  [240,230,140],
1338    lavender: [230,230,250],
1339    lavenderblush:  [255,240,245],
1340    lawngreen:  [124,252,0],
1341    lemonchiffon: [255,250,205],
1342    lightblue:  [173,216,230],
1343    lightcoral: [240,128,128],
1344    lightcyan:  [224,255,255],
1345    lightgoldenrodyellow: [250,250,210],
1346    lightgray:  [211,211,211],
1347    lightgreen: [144,238,144],
1348    lightgrey:  [211,211,211],
1349    lightpink:  [255,182,193],
1350    lightsalmon:  [255,160,122],
1351    lightseagreen:  [32,178,170],
1352    lightskyblue: [135,206,250],
1353    lightslategray: [119,136,153],
1354    lightslategrey: [119,136,153],
1355    lightsteelblue: [176,196,222],
1356    lightyellow:  [255,255,224],
1357    lime: [0,255,0],
1358    limegreen:  [50,205,50],
1359    linen:  [250,240,230],
1360    magenta:  [255,0,255],
1361    maroon: [128,0,0],
1362    mediumaquamarine: [102,205,170],
1363    mediumblue: [0,0,205],
1364    mediumorchid: [186,85,211],
1365    mediumpurple: [147,112,219],
1366    mediumseagreen: [60,179,113],
1367    mediumslateblue:  [123,104,238],
1368    mediumspringgreen:  [0,250,154],
1369    mediumturquoise:  [72,209,204],
1370    mediumvioletred:  [199,21,133],
1371    midnightblue: [25,25,112],
1372    mintcream:  [245,255,250],
1373    mistyrose:  [255,228,225],
1374    moccasin: [255,228,181],
1375    navajowhite:  [255,222,173],
1376    navy: [0,0,128],
1377    oldlace:  [253,245,230],
1378    olive:  [128,128,0],
1379    olivedrab:  [107,142,35],
1380    orange: [255,165,0],
1381    orangered:  [255,69,0],
1382    orchid: [218,112,214],
1383    palegoldenrod:  [238,232,170],
1384    palegreen:  [152,251,152],
1385    paleturquoise:  [175,238,238],
1386    palevioletred:  [219,112,147],
1387    papayawhip: [255,239,213],
1388    peachpuff:  [255,218,185],
1389    peru: [205,133,63],
1390    pink: [255,192,203],
1391    plum: [221,160,221],
1392    powderblue: [176,224,230],
1393    purple: [128,0,128],
1394    rebeccapurple: [102, 51, 153],
1395    red:  [255,0,0],
1396    rosybrown:  [188,143,143],
1397    royalblue:  [65,105,225],
1398    saddlebrown:  [139,69,19],
1399    salmon: [250,128,114],
1400    sandybrown: [244,164,96],
1401    seagreen: [46,139,87],
1402    seashell: [255,245,238],
1403    sienna: [160,82,45],
1404    silver: [192,192,192],
1405    skyblue:  [135,206,235],
1406    slateblue:  [106,90,205],
1407    slategray:  [112,128,144],
1408    slategrey:  [112,128,144],
1409    snow: [255,250,250],
1410    springgreen:  [0,255,127],
1411    steelblue:  [70,130,180],
1412    tan:  [210,180,140],
1413    teal: [0,128,128],
1414    thistle:  [216,191,216],
1415    tomato: [255,99,71],
1416    turquoise:  [64,224,208],
1417    violet: [238,130,238],
1418    wheat:  [245,222,179],
1419    white:  [255,255,255],
1420    whitesmoke: [245,245,245],
1421    yellow: [255,255,0],
1422    yellowgreen:  [154,205,50]
1423  };
1424  
1425  var reverseKeywords = {};
1426  for (var key in cssKeywords) {
1427    reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
1428  }
1429  
1430  },{}],5:[function(require,module,exports){
1431  var conversions = require(4);
1432  
1433  var convert = function() {
1434     return new Converter();
1435  }
1436  
1437  for (var func in conversions) {
1438    // export Raw versions

1439    convert[func + "Raw"] =  (function(func) {
1440      // accept array or plain args

1441      return function(arg) {
1442        if (typeof arg == "number")
1443          arg = Array.prototype.slice.call(arguments);
1444        return conversions[func](arg);
1445      }
1446    })(func);
1447  
1448    var pair = /(\w+)2(\w+)/.exec(func),
1449        from = pair[1],
1450        to = pair[2];
1451  
1452    // export rgb2hsl and ["rgb"]["hsl"]

1453    convert[from] = convert[from] || {};
1454  
1455    convert[from][to] = convert[func] = (function(func) { 
1456      return function(arg) {
1457        if (typeof arg == "number")
1458          arg = Array.prototype.slice.call(arguments);
1459        
1460        var val = conversions[func](arg);
1461        if (typeof val == "string" || val === undefined)
1462          return val; // keyword

1463  
1464        for (var i = 0; i < val.length; i++)
1465          val[i] = Math.round(val[i]);
1466        return val;
1467      }
1468    })(func);
1469  }
1470  
1471  
1472  /* Converter does lazy conversion and caching */

1473  var Converter = function() {
1474     this.convs = {};
1475  };
1476  
1477  /* Either get the values for a space or

1478    set the values for a space, depending on args */
1479  Converter.prototype.routeSpace = function(space, args) {
1480     var values = args[0];
1481     if (values === undefined) {
1482        // color.rgb()

1483        return this.getValues(space);
1484     }
1485     // color.rgb(10, 10, 10)

1486     if (typeof values == "number") {
1487        values = Array.prototype.slice.call(args);        
1488     }
1489  
1490     return this.setValues(space, values);
1491  };
1492    
1493  /* Set the values for a space, invalidating cache */

1494  Converter.prototype.setValues = function(space, values) {
1495     this.space = space;
1496     this.convs = {};
1497     this.convs[space] = values;
1498     return this;
1499  };
1500  
1501  /* Get the values for a space. If there's already

1502    a conversion for the space, fetch it, otherwise

1503    compute it */
1504  Converter.prototype.getValues = function(space) {
1505     var vals = this.convs[space];
1506     if (!vals) {
1507        var fspace = this.space,
1508            from = this.convs[fspace];
1509        vals = convert[fspace][space](from);
1510  
1511        this.convs[space] = vals;
1512     }
1513    return vals;
1514  };
1515  
1516  ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
1517     Converter.prototype[space] = function(vals) {
1518        return this.routeSpace(space, arguments);
1519     }
1520  });
1521  
1522  module.exports = convert;
1523  },{"4":4}],6:[function(require,module,exports){
1524  module.exports = {
1525      "aliceblue": [240, 248, 255],
1526      "antiquewhite": [250, 235, 215],
1527      "aqua": [0, 255, 255],
1528      "aquamarine": [127, 255, 212],
1529      "azure": [240, 255, 255],
1530      "beige": [245, 245, 220],
1531      "bisque": [255, 228, 196],
1532      "black": [0, 0, 0],
1533      "blanchedalmond": [255, 235, 205],
1534      "blue": [0, 0, 255],
1535      "blueviolet": [138, 43, 226],
1536      "brown": [165, 42, 42],
1537      "burlywood": [222, 184, 135],
1538      "cadetblue": [95, 158, 160],
1539      "chartreuse": [127, 255, 0],
1540      "chocolate": [210, 105, 30],
1541      "coral": [255, 127, 80],
1542      "cornflowerblue": [100, 149, 237],
1543      "cornsilk": [255, 248, 220],
1544      "crimson": [220, 20, 60],
1545      "cyan": [0, 255, 255],
1546      "darkblue": [0, 0, 139],
1547      "darkcyan": [0, 139, 139],
1548      "darkgoldenrod": [184, 134, 11],
1549      "darkgray": [169, 169, 169],
1550      "darkgreen": [0, 100, 0],
1551      "darkgrey": [169, 169, 169],
1552      "darkkhaki": [189, 183, 107],
1553      "darkmagenta": [139, 0, 139],
1554      "darkolivegreen": [85, 107, 47],
1555      "darkorange": [255, 140, 0],
1556      "darkorchid": [153, 50, 204],
1557      "darkred": [139, 0, 0],
1558      "darksalmon": [233, 150, 122],
1559      "darkseagreen": [143, 188, 143],
1560      "darkslateblue": [72, 61, 139],
1561      "darkslategray": [47, 79, 79],
1562      "darkslategrey": [47, 79, 79],
1563      "darkturquoise": [0, 206, 209],
1564      "darkviolet": [148, 0, 211],
1565      "deeppink": [255, 20, 147],
1566      "deepskyblue": [0, 191, 255],
1567      "dimgray": [105, 105, 105],
1568      "dimgrey": [105, 105, 105],
1569      "dodgerblue": [30, 144, 255],
1570      "firebrick": [178, 34, 34],
1571      "floralwhite": [255, 250, 240],
1572      "forestgreen": [34, 139, 34],
1573      "fuchsia": [255, 0, 255],
1574      "gainsboro": [220, 220, 220],
1575      "ghostwhite": [248, 248, 255],
1576      "gold": [255, 215, 0],
1577      "goldenrod": [218, 165, 32],
1578      "gray": [128, 128, 128],
1579      "green": [0, 128, 0],
1580      "greenyellow": [173, 255, 47],
1581      "grey": [128, 128, 128],
1582      "honeydew": [240, 255, 240],
1583      "hotpink": [255, 105, 180],
1584      "indianred": [205, 92, 92],
1585      "indigo": [75, 0, 130],
1586      "ivory": [255, 255, 240],
1587      "khaki": [240, 230, 140],
1588      "lavender": [230, 230, 250],
1589      "lavenderblush": [255, 240, 245],
1590      "lawngreen": [124, 252, 0],
1591      "lemonchiffon": [255, 250, 205],
1592      "lightblue": [173, 216, 230],
1593      "lightcoral": [240, 128, 128],
1594      "lightcyan": [224, 255, 255],
1595      "lightgoldenrodyellow": [250, 250, 210],
1596      "lightgray": [211, 211, 211],
1597      "lightgreen": [144, 238, 144],
1598      "lightgrey": [211, 211, 211],
1599      "lightpink": [255, 182, 193],
1600      "lightsalmon": [255, 160, 122],
1601      "lightseagreen": [32, 178, 170],
1602      "lightskyblue": [135, 206, 250],
1603      "lightslategray": [119, 136, 153],
1604      "lightslategrey": [119, 136, 153],
1605      "lightsteelblue": [176, 196, 222],
1606      "lightyellow": [255, 255, 224],
1607      "lime": [0, 255, 0],
1608      "limegreen": [50, 205, 50],
1609      "linen": [250, 240, 230],
1610      "magenta": [255, 0, 255],
1611      "maroon": [128, 0, 0],
1612      "mediumaquamarine": [102, 205, 170],
1613      "mediumblue": [0, 0, 205],
1614      "mediumorchid": [186, 85, 211],
1615      "mediumpurple": [147, 112, 219],
1616      "mediumseagreen": [60, 179, 113],
1617      "mediumslateblue": [123, 104, 238],
1618      "mediumspringgreen": [0, 250, 154],
1619      "mediumturquoise": [72, 209, 204],
1620      "mediumvioletred": [199, 21, 133],
1621      "midnightblue": [25, 25, 112],
1622      "mintcream": [245, 255, 250],
1623      "mistyrose": [255, 228, 225],
1624      "moccasin": [255, 228, 181],
1625      "navajowhite": [255, 222, 173],
1626      "navy": [0, 0, 128],
1627      "oldlace": [253, 245, 230],
1628      "olive": [128, 128, 0],
1629      "olivedrab": [107, 142, 35],
1630      "orange": [255, 165, 0],
1631      "orangered": [255, 69, 0],
1632      "orchid": [218, 112, 214],
1633      "palegoldenrod": [238, 232, 170],
1634      "palegreen": [152, 251, 152],
1635      "paleturquoise": [175, 238, 238],
1636      "palevioletred": [219, 112, 147],
1637      "papayawhip": [255, 239, 213],
1638      "peachpuff": [255, 218, 185],
1639      "peru": [205, 133, 63],
1640      "pink": [255, 192, 203],
1641      "plum": [221, 160, 221],
1642      "powderblue": [176, 224, 230],
1643      "purple": [128, 0, 128],
1644      "rebeccapurple": [102, 51, 153],
1645      "red": [255, 0, 0],
1646      "rosybrown": [188, 143, 143],
1647      "royalblue": [65, 105, 225],
1648      "saddlebrown": [139, 69, 19],
1649      "salmon": [250, 128, 114],
1650      "sandybrown": [244, 164, 96],
1651      "seagreen": [46, 139, 87],
1652      "seashell": [255, 245, 238],
1653      "sienna": [160, 82, 45],
1654      "silver": [192, 192, 192],
1655      "skyblue": [135, 206, 235],
1656      "slateblue": [106, 90, 205],
1657      "slategray": [112, 128, 144],
1658      "slategrey": [112, 128, 144],
1659      "snow": [255, 250, 250],
1660      "springgreen": [0, 255, 127],
1661      "steelblue": [70, 130, 180],
1662      "tan": [210, 180, 140],
1663      "teal": [0, 128, 128],
1664      "thistle": [216, 191, 216],
1665      "tomato": [255, 99, 71],
1666      "turquoise": [64, 224, 208],
1667      "violet": [238, 130, 238],
1668      "wheat": [245, 222, 179],
1669      "white": [255, 255, 255],
1670      "whitesmoke": [245, 245, 245],
1671      "yellow": [255, 255, 0],
1672      "yellowgreen": [154, 205, 50]
1673  };
1674  },{}],7:[function(require,module,exports){
1675  /**

1676   * @namespace Chart

1677   */
1678  var Chart = require(26)();
1679  
1680  require(25)(Chart);
1681  require(24)(Chart);
1682  require(21)(Chart);
1683  require(22)(Chart);
1684  require(23)(Chart);
1685  require(27)(Chart);
1686  require(31)(Chart);
1687  require(29)(Chart);
1688  require(30)(Chart);
1689  require(32)(Chart);
1690  require(28)(Chart);
1691  require(33)(Chart);
1692  
1693  require(34)(Chart);
1694  require(35)(Chart);
1695  require(36)(Chart);
1696  require(37)(Chart);
1697  
1698  require(40)(Chart);
1699  require(38)(Chart);
1700  require(39)(Chart);
1701  require(41)(Chart);
1702  require(42)(Chart);
1703  require(43)(Chart);
1704  
1705  // Controllers must be loaded after elements

1706  // See Chart.core.datasetController.dataElementType

1707  require(15)(Chart);
1708  require(16)(Chart);
1709  require(17)(Chart);
1710  require(18)(Chart);
1711  require(19)(Chart);
1712  require(20)(Chart);
1713  
1714  require(8)(Chart);
1715  require(9)(Chart);
1716  require(10)(Chart);
1717  require(11)(Chart);
1718  require(12)(Chart);
1719  require(13)(Chart);
1720  require(14)(Chart);
1721  
1722  window.Chart = module.exports = Chart;
1723  
1724  },{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"34":34,"35":35,"36":36,"37":37,"38":38,"39":39,"40":40,"41":41,"42":42,"43":43,"8":8,"9":9}],8:[function(require,module,exports){
1725  "use strict";
1726  
1727  module.exports = function(Chart) {
1728  
1729      Chart.Bar = function(context, config) {
1730          config.type = 'bar';
1731  
1732          return new Chart(context, config);
1733      };
1734  
1735  };
1736  },{}],9:[function(require,module,exports){
1737  "use strict";
1738  
1739  module.exports = function(Chart) {
1740  
1741      Chart.Bubble = function(context, config) {
1742          config.type = 'bubble';
1743          return new Chart(context, config);
1744      };
1745  
1746  };
1747  },{}],10:[function(require,module,exports){
1748  "use strict";
1749  
1750  module.exports = function(Chart) {
1751  
1752      Chart.Doughnut = function(context, config) {
1753          config.type = 'doughnut';
1754  
1755          return new Chart(context, config);
1756      };
1757  
1758  };
1759  },{}],11:[function(require,module,exports){
1760  "use strict";
1761  
1762  module.exports = function(Chart) {
1763  
1764      Chart.Line = function(context, config) {
1765          config.type = 'line';
1766  
1767          return new Chart(context, config);
1768      };
1769  
1770  };
1771  },{}],12:[function(require,module,exports){
1772  "use strict";
1773  
1774  module.exports = function(Chart) {
1775  
1776      Chart.PolarArea = function(context, config) {
1777          config.type = 'polarArea';
1778  
1779          return new Chart(context, config);
1780      };
1781  
1782  };
1783  },{}],13:[function(require,module,exports){
1784  "use strict";
1785  
1786  module.exports = function(Chart) {
1787      
1788      Chart.Radar = function(context, config) {
1789          config.options = Chart.helpers.configMerge({ aspectRatio: 1 }, config.options);
1790          config.type = 'radar';
1791  
1792          return new Chart(context, config);
1793      };
1794  
1795  };
1796  
1797  },{}],14:[function(require,module,exports){
1798  "use strict";
1799  
1800  module.exports = function(Chart) {
1801  
1802      var defaultConfig = {
1803          hover: {
1804              mode: 'single'
1805          },
1806  
1807          scales: {
1808              xAxes: [{
1809                  type: "linear", // scatter should not use a category axis
1810                  position: "bottom",
1811                  id: "x-axis-1" // need an ID so datasets can reference the scale
1812              }],
1813              yAxes: [{
1814                  type: "linear",
1815                  position: "left",
1816                  id: "y-axis-1"
1817              }]
1818          },
1819  
1820          tooltips: {
1821              callbacks: {
1822                  title: function(tooltipItems, data) {
1823                      // Title doesn't make sense for scatter since we format the data as a point

1824                      return '';
1825                  },
1826                  label: function(tooltipItem, data) {
1827                      return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')';
1828                  }
1829              }
1830          }
1831      };
1832  
1833      // Register the default config for this type

1834      Chart.defaults.scatter = defaultConfig;
1835  
1836      // Scatter charts use line controllers

1837      Chart.controllers.scatter = Chart.controllers.line;
1838  
1839      Chart.Scatter = function(context, config) {
1840          config.type = 'scatter';
1841          return new Chart(context, config);
1842      };
1843  
1844  };
1845  },{}],15:[function(require,module,exports){
1846  "use strict";
1847  
1848  module.exports = function(Chart) {
1849  
1850      var helpers = Chart.helpers;
1851  
1852      Chart.defaults.bar = {
1853          hover: {
1854              mode: "label"
1855          },
1856  
1857          scales: {
1858              xAxes: [{
1859                  type: "category",
1860  
1861                  // Specific to Bar Controller

1862                  categoryPercentage: 0.8,
1863                  barPercentage: 0.9,
1864  
1865                  // grid line settings

1866                  gridLines: {
1867                      offsetGridLines: true
1868                  }
1869              }],
1870              yAxes: [{
1871                  type: "linear"
1872              }]
1873          }
1874      };
1875  
1876      Chart.controllers.bar = Chart.DatasetController.extend({
1877  
1878          dataElementType: Chart.elements.Rectangle,
1879  
1880          initialize: function(chart, datasetIndex) {
1881              Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex);
1882  
1883              // Use this to indicate that this is a bar dataset.

1884              this.getMeta().bar = true;
1885          },
1886  
1887          // Get the number of datasets that display bars. We use this to correctly calculate the bar width

1888          getBarCount: function getBarCount() {
1889              var me = this;
1890              var barCount = 0;
1891              helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) {
1892                  var meta = me.chart.getDatasetMeta(datasetIndex);
1893                  if (meta.bar && me.chart.isDatasetVisible(datasetIndex)) {
1894                      ++barCount;
1895                  }
1896              }, me);
1897              return barCount;
1898          },
1899  
1900          update: function update(reset) {
1901              var me = this;
1902              helpers.each(me.getMeta().data, function(rectangle, index) {
1903                  me.updateElement(rectangle, index, reset);
1904              }, me);
1905          },
1906  
1907          updateElement: function updateElement(rectangle, index, reset) {
1908              var me = this;
1909              var meta = me.getMeta();
1910              var xScale = me.getScaleForId(meta.xAxisID);
1911              var yScale = me.getScaleForId(meta.yAxisID);
1912              var scaleBase = yScale.getBasePixel();
1913              var rectangleElementOptions = me.chart.options.elements.rectangle;
1914              var custom = rectangle.custom || {};
1915              var dataset = me.getDataset();
1916  
1917              helpers.extend(rectangle, {
1918                  // Utility

1919                  _xScale: xScale,
1920                  _yScale: yScale,
1921                  _datasetIndex: me.index,
1922                  _index: index,
1923  
1924                  // Desired view properties

1925                  _model: {
1926                      x: me.calculateBarX(index, me.index),
1927                      y: reset ? scaleBase : me.calculateBarY(index, me.index),
1928  
1929                      // Tooltip

1930                      label: me.chart.data.labels[index],
1931                      datasetLabel: dataset.label,
1932  
1933                      // Appearance

1934                      base: reset ? scaleBase : me.calculateBarBase(me.index, index),
1935                      width: me.calculateBarWidth(index),
1936                      backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor),
1937                      borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped,
1938                      borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor),
1939                      borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth)
1940                  }
1941              });
1942              rectangle.pivot();
1943          },
1944  
1945          calculateBarBase: function(datasetIndex, index) {
1946              var me = this;
1947              var meta = me.getMeta();
1948              var yScale = me.getScaleForId(meta.yAxisID);
1949              var base = 0;
1950  
1951              if (yScale.options.stacked) {
1952                  var chart = me.chart;
1953                  var datasets = chart.data.datasets;
1954                  var value = datasets[datasetIndex].data[index];
1955  
1956                  if (value < 0) {
1957                      for (var i = 0; i < datasetIndex; i++) {
1958                          var negDS = datasets[i];
1959                          var negDSMeta = chart.getDatasetMeta(i);
1960                          if (negDSMeta.bar && negDSMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
1961                              base += negDS.data[index] < 0 ? negDS.data[index] : 0;
1962                          }
1963                      }
1964                  } else {
1965                      for (var j = 0; j < datasetIndex; j++) {
1966                          var posDS = datasets[j];
1967                          var posDSMeta = chart.getDatasetMeta(j);
1968                          if (posDSMeta.bar && posDSMeta.yAxisID === yScale.id && chart.isDatasetVisible(j)) {
1969                              base += posDS.data[index] > 0 ? posDS.data[index] : 0;
1970                          }
1971                      }
1972                  }
1973  
1974                  return yScale.getPixelForValue(base);
1975              }
1976  
1977              return yScale.getBasePixel();
1978          },
1979  
1980          getRuler: function(index) {
1981              var me = this;
1982              var meta = me.getMeta();
1983              var xScale = me.getScaleForId(meta.xAxisID);
1984              var datasetCount = me.getBarCount();
1985  
1986              var tickWidth;
1987  
1988              if (xScale.options.type === 'category') {
1989                  tickWidth = xScale.getPixelForTick(index + 1) - xScale.getPixelForTick(index);
1990              } else {
1991                  // Average width

1992                  tickWidth = xScale.width / xScale.ticks.length;
1993              }
1994              var categoryWidth = tickWidth * xScale.options.categoryPercentage;
1995              var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2;
1996              var fullBarWidth = categoryWidth / datasetCount;
1997  
1998              if (xScale.ticks.length !== me.chart.data.labels.length) {
1999                  var perc = xScale.ticks.length / me.chart.data.labels.length;
2000                  fullBarWidth = fullBarWidth * perc;
2001              }
2002  
2003              var barWidth = fullBarWidth * xScale.options.barPercentage;
2004              var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage);
2005  
2006              return {
2007                  datasetCount: datasetCount,
2008                  tickWidth: tickWidth,
2009                  categoryWidth: categoryWidth,
2010                  categorySpacing: categorySpacing,
2011                  fullBarWidth: fullBarWidth,
2012                  barWidth: barWidth,
2013                  barSpacing: barSpacing
2014              };
2015          },
2016  
2017          calculateBarWidth: function(index) {
2018              var xScale = this.getScaleForId(this.getMeta().xAxisID);
2019              var ruler = this.getRuler(index);
2020              return xScale.options.stacked ? ruler.categoryWidth : ruler.barWidth;
2021          },
2022  
2023          // Get bar index from the given dataset index accounting for the fact that not all bars are visible

2024          getBarIndex: function(datasetIndex) {
2025              var barIndex = 0;
2026              var meta, j;
2027  
2028              for (j = 0; j < datasetIndex; ++j) {
2029                  meta = this.chart.getDatasetMeta(j);
2030                  if (meta.bar && this.chart.isDatasetVisible(j)) {
2031                      ++barIndex;
2032                  }
2033              }
2034  
2035              return barIndex;
2036          },
2037  
2038          calculateBarX: function(index, datasetIndex) {
2039              var me = this;
2040              var meta = me.getMeta();
2041              var xScale = me.getScaleForId(meta.xAxisID);
2042              var barIndex = me.getBarIndex(datasetIndex);
2043  
2044              var ruler = me.getRuler(index);
2045              var leftTick = xScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo);
2046              leftTick -= me.chart.isCombo ? (ruler.tickWidth / 2) : 0;
2047  
2048              if (xScale.options.stacked) {
2049                  return leftTick + (ruler.categoryWidth / 2) + ruler.categorySpacing;
2050              }
2051  
2052              return leftTick +
2053                  (ruler.barWidth / 2) +
2054                  ruler.categorySpacing +
2055                  (ruler.barWidth * barIndex) +
2056                  (ruler.barSpacing / 2) +
2057                  (ruler.barSpacing * barIndex);
2058          },
2059  
2060          calculateBarY: function(index, datasetIndex) {
2061              var me = this;
2062              var meta = me.getMeta();
2063              var yScale = me.getScaleForId(meta.yAxisID);
2064              var value = me.getDataset().data[index];
2065  
2066              if (yScale.options.stacked) {
2067  
2068                  var sumPos = 0,
2069                      sumNeg = 0;
2070  
2071                  for (var i = 0; i < datasetIndex; i++) {
2072                      var ds = me.chart.data.datasets[i];
2073                      var dsMeta = me.chart.getDatasetMeta(i);
2074                      if (dsMeta.bar && dsMeta.yAxisID === yScale.id && me.chart.isDatasetVisible(i)) {
2075                          if (ds.data[index] < 0) {
2076                              sumNeg += ds.data[index] || 0;
2077                          } else {
2078                              sumPos += ds.data[index] || 0;
2079                          }
2080                      }
2081                  }
2082  
2083                  if (value < 0) {
2084                      return yScale.getPixelForValue(sumNeg + value);
2085                  } else {
2086                      return yScale.getPixelForValue(sumPos + value);
2087                  }
2088              }
2089  
2090              return yScale.getPixelForValue(value);
2091          },
2092  
2093          draw: function(ease) {
2094              var me = this;
2095              var easingDecimal = ease || 1;
2096              helpers.each(me.getMeta().data, function(rectangle, index) {
2097                  var d = me.getDataset().data[index];
2098                  if (d !== null && d !== undefined && !isNaN(d)) {
2099                      rectangle.transition(easingDecimal).draw();
2100                  }
2101              }, me);
2102          },
2103  
2104          setHoverStyle: function(rectangle) {
2105              var dataset = this.chart.data.datasets[rectangle._datasetIndex];
2106              var index = rectangle._index;
2107  
2108              var custom = rectangle.custom || {};
2109              var model = rectangle._model;
2110              model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
2111              model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor));
2112              model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
2113          },
2114  
2115          removeHoverStyle: function(rectangle) {
2116              var dataset = this.chart.data.datasets[rectangle._datasetIndex];
2117              var index = rectangle._index;
2118              var custom = rectangle.custom || {};
2119              var model = rectangle._model;
2120              var rectangleElementOptions = this.chart.options.elements.rectangle;
2121  
2122              model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor);
2123              model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor);
2124              model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth);
2125          }
2126  
2127      });
2128  
2129  
2130      // including horizontalBar in the bar file, instead of a file of its own

2131      // it extends bar (like pie extends doughnut)

2132      Chart.defaults.horizontalBar = {
2133          hover: {
2134              mode: "label"
2135          },
2136  
2137          scales: {
2138              xAxes: [{
2139                  type: "linear",
2140                  position: "bottom"
2141              }],
2142              yAxes: [{
2143                  position: "left",
2144                  type: "category",
2145  
2146                  // Specific to Horizontal Bar Controller

2147                  categoryPercentage: 0.8,
2148                  barPercentage: 0.9,
2149  
2150                  // grid line settings

2151                  gridLines: {
2152                      offsetGridLines: true
2153                  }
2154              }]
2155          },
2156          elements: {
2157              rectangle: {
2158                  borderSkipped: 'left'
2159              }
2160          },
2161          tooltips: {
2162              callbacks: {
2163                  title: function(tooltipItems, data) {
2164                      // Pick first xLabel for now

2165                      var title = '';
2166  
2167                      if (tooltipItems.length > 0) {
2168                          if (tooltipItems[0].yLabel) {
2169                              title = tooltipItems[0].yLabel;
2170                          } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) {
2171                              title = data.labels[tooltipItems[0].index];
2172                          }
2173                      }
2174  
2175                      return title;
2176                  },
2177                  label: function(tooltipItem, data) {
2178                      var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
2179                  return datasetLabel + ': ' + tooltipItem.xLabel;
2180                  }
2181              }
2182          }
2183      };
2184  
2185      Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
2186          updateElement: function updateElement(rectangle, index, reset, numBars) {
2187              var me = this;
2188              var meta = me.getMeta();
2189              var xScale = me.getScaleForId(meta.xAxisID);
2190              var yScale = me.getScaleForId(meta.yAxisID);
2191              var scaleBase = xScale.getBasePixel();
2192              var custom = rectangle.custom || {};
2193              var dataset = me.getDataset();
2194              var rectangleElementOptions = me.chart.options.elements.rectangle;
2195  
2196              helpers.extend(rectangle, {
2197                  // Utility

2198                  _xScale: xScale,
2199                  _yScale: yScale,
2200                  _datasetIndex: me.index,
2201                  _index: index,
2202  
2203                  // Desired view properties

2204                  _model: {
2205                      x: reset ? scaleBase : me.calculateBarX(index, me.index),
2206                      y: me.calculateBarY(index, me.index),
2207  
2208                      // Tooltip

2209                      label: me.chart.data.labels[index],
2210                      datasetLabel: dataset.label,
2211  
2212                      // Appearance

2213                      base: reset ? scaleBase : me.calculateBarBase(me.index, index),
2214                      height: me.calculateBarHeight(index),
2215                      backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor),
2216                      borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped,
2217                      borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor),
2218                      borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth)
2219                  },
2220  
2221                  draw: function () {
2222                      var ctx = this._chart.ctx;
2223                      var vm = this._view;
2224  
2225                      var halfHeight = vm.height / 2,
2226                          topY = vm.y - halfHeight,
2227                          bottomY = vm.y + halfHeight,
2228                          right = vm.base - (vm.base - vm.x),
2229                          halfStroke = vm.borderWidth / 2;
2230  
2231                      // Canvas doesn't allow us to stroke inside the width so we can

2232                      // adjust the sizes to fit if we're setting a stroke on the line

2233                      if (vm.borderWidth) {
2234                          topY += halfStroke;
2235                          bottomY -= halfStroke;
2236                          right += halfStroke;
2237                      }
2238  
2239                      ctx.beginPath();
2240  
2241                      ctx.fillStyle = vm.backgroundColor;
2242                      ctx.strokeStyle = vm.borderColor;
2243                      ctx.lineWidth = vm.borderWidth;
2244  
2245                      // Corner points, from bottom-left to bottom-right clockwise

2246                      // | 1 2 |

2247                      // | 0 3 |

2248                      var corners = [
2249                          [vm.base, bottomY],
2250                          [vm.base, topY],
2251                          [right, topY],
2252                          [right, bottomY]
2253                      ];
2254  
2255                      // Find first (starting) corner with fallback to 'bottom'

2256                      var borders = ['bottom', 'left', 'top', 'right'];
2257                      var startCorner = borders.indexOf(vm.borderSkipped, 0);
2258                      if (startCorner === -1)
2259                          startCorner = 0;
2260  
2261  					function cornerAt(index) {
2262                          return corners[(startCorner + index) % 4];
2263                      }
2264  
2265                      // Draw rectangle from 'startCorner'

2266                      ctx.moveTo.apply(ctx, cornerAt(0));
2267                      for (var i = 1; i < 4; i++)
2268                          ctx.lineTo.apply(ctx, cornerAt(i));
2269  
2270                      ctx.fill();
2271                      if (vm.borderWidth) {
2272                          ctx.stroke();
2273                      }
2274                  },
2275  
2276                  inRange: function (mouseX, mouseY) {
2277                      var vm = this._view;
2278                      var inRange = false;
2279  
2280                      if (vm) {
2281                          if (vm.x < vm.base) {
2282                              inRange = (mouseY >= vm.y - vm.height / 2 && mouseY <= vm.y + vm.height / 2) && (mouseX >= vm.x && mouseX <= vm.base);
2283                          } else {
2284                              inRange = (mouseY >= vm.y - vm.height / 2 && mouseY <= vm.y + vm.height / 2) && (mouseX >= vm.base && mouseX <= vm.x);
2285                          }
2286                      }
2287  
2288                      return inRange;
2289                  }
2290              });
2291  
2292              rectangle.pivot();
2293          },
2294  
2295          calculateBarBase: function (datasetIndex, index) {
2296              var me = this;
2297              var meta = me.getMeta();
2298              var xScale = me.getScaleForId(meta.xAxisID);
2299              var base = 0;
2300  
2301              if (xScale.options.stacked) {
2302  
2303                  var value = me.chart.data.datasets[datasetIndex].data[index];
2304  
2305                  if (value < 0) {
2306                      for (var i = 0; i < datasetIndex; i++) {
2307                          var negDS = me.chart.data.datasets[i];
2308                          var negDSMeta = me.chart.getDatasetMeta(i);
2309                          if (negDSMeta.bar && negDSMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(i)) {
2310                              base += negDS.data[index] < 0 ? negDS.data[index] : 0;
2311                          }
2312                      }
2313                  } else {
2314                      for (var j = 0; j < datasetIndex; j++) {
2315                          var posDS = me.chart.data.datasets[j];
2316                          var posDSMeta = me.chart.getDatasetMeta(j);
2317                          if (posDSMeta.bar && posDSMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(j)) {
2318                              base += posDS.data[index] > 0 ? posDS.data[index] : 0;
2319                          }
2320                      }
2321                  }
2322  
2323                  return xScale.getPixelForValue(base);
2324              }
2325  
2326              return xScale.getBasePixel();
2327          },
2328  
2329          getRuler: function (index) {
2330              var me = this;
2331              var meta = me.getMeta();
2332              var yScale = me.getScaleForId(meta.yAxisID);
2333              var datasetCount = me.getBarCount();
2334  
2335              var tickHeight;
2336              if (yScale.options.type === 'category') {
2337                  tickHeight = yScale.getPixelForTick(index + 1) - yScale.getPixelForTick(index);
2338              } else {
2339                  // Average width

2340                  tickHeight = yScale.width / yScale.ticks.length;
2341              }
2342              var categoryHeight = tickHeight * yScale.options.categoryPercentage;
2343              var categorySpacing = (tickHeight - (tickHeight * yScale.options.categoryPercentage)) / 2;
2344              var fullBarHeight = categoryHeight / datasetCount;
2345  
2346              if (yScale.ticks.length !== me.chart.data.labels.length) {
2347                  var perc = yScale.ticks.length / me.chart.data.labels.length;
2348                  fullBarHeight = fullBarHeight * perc;
2349              }
2350  
2351              var barHeight = fullBarHeight * yScale.options.barPercentage;
2352              var barSpacing = fullBarHeight - (fullBarHeight * yScale.options.barPercentage);
2353  
2354              return {
2355                  datasetCount: datasetCount,
2356                  tickHeight: tickHeight,
2357                  categoryHeight: categoryHeight,
2358                  categorySpacing: categorySpacing,
2359                  fullBarHeight: fullBarHeight,
2360                  barHeight: barHeight,
2361                  barSpacing: barSpacing,
2362              };
2363          },
2364  
2365          calculateBarHeight: function (index) {
2366              var me = this;
2367              var yScale = me.getScaleForId(me.getMeta().yAxisID);
2368              var ruler = me.getRuler(index);
2369              return yScale.options.stacked ? ruler.categoryHeight : ruler.barHeight;
2370          },
2371  
2372          calculateBarX: function (index, datasetIndex) {
2373              var me = this;
2374              var meta = me.getMeta();
2375              var xScale = me.getScaleForId(meta.xAxisID);
2376              var value = me.getDataset().data[index];
2377  
2378              if (xScale.options.stacked) {
2379  
2380                  var sumPos = 0,
2381                      sumNeg = 0;
2382  
2383                  for (var i = 0; i < datasetIndex; i++) {
2384                      var ds = me.chart.data.datasets[i];
2385                      var dsMeta = me.chart.getDatasetMeta(i);
2386                      if (dsMeta.bar && dsMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(i)) {
2387                          if (ds.data[index] < 0) {
2388                              sumNeg += ds.data[index] || 0;
2389                          } else {
2390                              sumPos += ds.data[index] || 0;
2391                          }
2392                      }
2393                  }
2394  
2395                  if (value < 0) {
2396                      return xScale.getPixelForValue(sumNeg + value);
2397                  } else {
2398                      return xScale.getPixelForValue(sumPos + value);
2399                  }
2400              }
2401  
2402              return xScale.getPixelForValue(value);
2403          },
2404  
2405          calculateBarY: function (index, datasetIndex) {
2406              var me = this;
2407              var meta = me.getMeta();
2408              var yScale = me.getScaleForId(meta.yAxisID);
2409              var barIndex = me.getBarIndex(datasetIndex);
2410  
2411              var ruler = me.getRuler(index);
2412              var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo);
2413              topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0;
2414  
2415              if (yScale.options.stacked) {
2416                  return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing;
2417              }
2418  
2419              return topTick +
2420                  (ruler.barHeight / 2) +
2421                  ruler.categorySpacing +
2422                  (ruler.barHeight * barIndex) +
2423                  (ruler.barSpacing / 2) +
2424                  (ruler.barSpacing * barIndex);
2425          }
2426      });
2427  };
2428  
2429  },{}],16:[function(require,module,exports){
2430  "use strict";
2431  
2432  module.exports = function(Chart) {
2433  
2434      var helpers = Chart.helpers;
2435  
2436      Chart.defaults.bubble = {
2437          hover: {
2438              mode: "single"
2439          },
2440  
2441          scales: {
2442              xAxes: [{
2443                  type: "linear", // bubble should probably use a linear scale by default
2444                  position: "bottom",
2445                  id: "x-axis-0" // need an ID so datasets can reference the scale
2446              }],
2447              yAxes: [{
2448                  type: "linear",
2449                  position: "left",
2450                  id: "y-axis-0"
2451              }]
2452          },
2453  
2454          tooltips: {
2455              callbacks: {
2456                  title: function(tooltipItems, data) {
2457                      // Title doesn't make sense for scatter since we format the data as a point

2458                      return '';
2459                  },
2460                  label: function(tooltipItem, data) {
2461                      var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
2462                      var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
2463                      return datasetLabel + ': (' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.r + ')';
2464                  }
2465              }
2466          }
2467      };
2468  
2469      Chart.controllers.bubble = Chart.DatasetController.extend({
2470  
2471          dataElementType: Chart.elements.Point,
2472  
2473          update: function update(reset) {
2474              var me = this;
2475              var meta = me.getMeta();
2476              var points = meta.data;
2477  
2478              // Update Points

2479              helpers.each(points, function(point, index) {
2480                  me.updateElement(point, index, reset);
2481              });
2482          },
2483  
2484          updateElement: function(point, index, reset) {
2485              var me = this;
2486              var meta = me.getMeta();
2487              var xScale = me.getScaleForId(meta.xAxisID);
2488              var yScale = me.getScaleForId(meta.yAxisID);
2489  
2490              var custom = point.custom || {};
2491              var dataset = me.getDataset();
2492              var data = dataset.data[index];
2493              var pointElementOptions = me.chart.options.elements.point;
2494              var dsIndex = me.index;
2495  
2496              helpers.extend(point, {
2497                  // Utility

2498                  _xScale: xScale,
2499                  _yScale: yScale,
2500                  _datasetIndex: dsIndex,
2501                  _index: index,
2502  
2503                  // Desired view properties

2504                  _model: {
2505                      x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(data, index, dsIndex, me.chart.isCombo),
2506                      y: reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex),
2507                      // Appearance

2508                      radius: reset ? 0 : custom.radius ? custom.radius : me.getRadius(data),
2509  
2510                      // Tooltip

2511                      hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius)
2512                  }
2513              });
2514  
2515              // Trick to reset the styles of the point

2516              Chart.DatasetController.prototype.removeHoverStyle.call(me, point, pointElementOptions);
2517  
2518              var model = point._model;
2519              model.skip = custom.skip ? custom.skip : (isNaN(model.x) || isNaN(model.y));
2520  
2521              point.pivot();
2522          },
2523  
2524          getRadius: function(value) {
2525              return value.r || this.chart.options.elements.point.radius;
2526          },
2527  
2528          setHoverStyle: function(point) {
2529              var me = this;
2530              Chart.DatasetController.prototype.setHoverStyle.call(me, point);
2531  
2532              // Radius

2533              var dataset = me.chart.data.datasets[point._datasetIndex];
2534              var index = point._index;
2535              var custom = point.custom || {};
2536              var model = point._model;
2537              model.radius = custom.hoverRadius ? custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, me.chart.options.elements.point.hoverRadius)) + me.getRadius(dataset.data[index]);
2538          },
2539  
2540          removeHoverStyle: function(point) {
2541              var me = this;
2542              Chart.DatasetController.prototype.removeHoverStyle.call(me, point, me.chart.options.elements.point);
2543  
2544              var dataVal = me.chart.data.datasets[point._datasetIndex].data[point._index];
2545              var custom = point.custom || {};
2546              var model = point._model;
2547  
2548              model.radius = custom.radius ? custom.radius : me.getRadius(dataVal);
2549          }
2550      });
2551  };
2552  
2553  },{}],17:[function(require,module,exports){
2554  "use strict";
2555  
2556  module.exports = function(Chart) {
2557  
2558      var helpers = Chart.helpers,
2559          defaults = Chart.defaults;
2560  
2561      defaults.doughnut = {
2562          animation: {
2563              //Boolean - Whether we animate the rotation of the Doughnut

2564              animateRotate: true,
2565              //Boolean - Whether we animate scaling the Doughnut from the centre

2566              animateScale: false
2567          },
2568          aspectRatio: 1,
2569          hover: {
2570              mode: 'single'
2571          },
2572          legendCallback: function(chart) {
2573              var text = [];
2574              text.push('<ul class="' + chart.id + '-legend">');
2575  
2576              var data = chart.data;
2577              var datasets = data.datasets;
2578              var labels = data.labels;
2579  
2580              if (datasets.length) {
2581                  for (var i = 0; i < datasets[0].data.length; ++i) {
2582                      text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
2583                      if (labels[i]) {
2584                          text.push(labels[i]);
2585                      }
2586                      text.push('</li>');
2587                  }
2588              }
2589  
2590              text.push('</ul>');
2591              return text.join("");
2592          },
2593          legend: {
2594              labels: {
2595                  generateLabels: function(chart) {
2596                      var data = chart.data;
2597                      if (data.labels.length && data.datasets.length) {
2598                          return data.labels.map(function(label, i) {
2599                              var meta = chart.getDatasetMeta(0);
2600                              var ds = data.datasets[0];
2601                              var arc = meta.data[i];
2602                              var custom = arc.custom || {};
2603                              var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
2604                              var arcOpts = chart.options.elements.arc;
2605                              var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
2606                              var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
2607                              var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
2608  
2609                              return {
2610                                  text: label,
2611                                  fillStyle: fill,
2612                                  strokeStyle: stroke,
2613                                  lineWidth: bw,
2614                                  hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
2615  
2616                                  // Extra data used for toggling the correct item

2617                                  index: i
2618                              };
2619                          });
2620                      } else {
2621                          return [];
2622                      }
2623                  }
2624              },
2625  
2626              onClick: function(e, legendItem) {
2627                  var index = legendItem.index;
2628                  var chart = this.chart;
2629                  var i, ilen, meta;
2630  
2631                  for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
2632                      meta = chart.getDatasetMeta(i);
2633                      meta.data[index].hidden = !meta.data[index].hidden;
2634                  }
2635  
2636                  chart.update();
2637              }
2638          },
2639  
2640          //The percentage of the chart that we cut out of the middle.

2641          cutoutPercentage: 50,
2642  
2643          //The rotation of the chart, where the first data arc begins.

2644          rotation: Math.PI * -0.5,
2645  
2646          //The total circumference of the chart.

2647          circumference: Math.PI * 2.0,
2648  
2649          // Need to override these to give a nice default

2650          tooltips: {
2651              callbacks: {
2652                  title: function() {
2653                      return '';
2654                  },
2655                  label: function(tooltipItem, data) {
2656                      return data.labels[tooltipItem.index] + ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
2657                  }
2658              }
2659          }
2660      };
2661  
2662      defaults.pie = helpers.clone(defaults.doughnut);
2663      helpers.extend(defaults.pie, {
2664          cutoutPercentage: 0
2665      });
2666  
2667  
2668      Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
2669  
2670          dataElementType: Chart.elements.Arc,
2671  
2672          linkScales: helpers.noop,
2673  
2674          // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly

2675          getRingIndex: function getRingIndex(datasetIndex) {
2676              var ringIndex = 0;
2677  
2678              for (var j = 0; j < datasetIndex; ++j) {
2679                  if (this.chart.isDatasetVisible(j)) {
2680                      ++ringIndex;
2681                  }
2682              }
2683  
2684              return ringIndex;
2685          },
2686  
2687          update: function update(reset) {
2688              var me = this;
2689              var chart = me.chart,
2690                  chartArea = chart.chartArea,
2691                  opts = chart.options,
2692                  arcOpts = opts.elements.arc,
2693                  availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth,
2694                  availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth,
2695                  minSize = Math.min(availableWidth, availableHeight),
2696                  offset = {
2697                      x: 0,
2698                      y: 0
2699                  },
2700                  meta = me.getMeta(),
2701                  cutoutPercentage = opts.cutoutPercentage,
2702                  circumference = opts.circumference;
2703  
2704              // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc

2705              if (circumference < Math.PI * 2.0) {
2706                  var startAngle = opts.rotation % (Math.PI * 2.0);
2707                  startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
2708                  var endAngle = startAngle + circumference;
2709                  var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
2710                  var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
2711                  var contains0 = (startAngle <= 0 && 0 <= endAngle) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
2712                  var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
2713                  var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
2714                  var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
2715                  var cutout = cutoutPercentage / 100.0;
2716                  var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
2717                  var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
2718                  var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
2719                  minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
2720                  offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
2721              }
2722  
2723              chart.outerRadius = Math.max(minSize / 2, 0);
2724              chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 1, 0);
2725              chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
2726              chart.offsetX = offset.x * chart.outerRadius;
2727              chart.offsetY = offset.y * chart.outerRadius;
2728  
2729              meta.total = me.calculateTotal();
2730  
2731              me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
2732              me.innerRadius = me.outerRadius - chart.radiusLength;
2733  
2734              helpers.each(meta.data, function(arc, index) {
2735                  me.updateElement(arc, index, reset);
2736              });
2737          },
2738  
2739          updateElement: function(arc, index, reset) {
2740              var me = this;
2741              var chart = me.chart,
2742                  chartArea = chart.chartArea,
2743                  opts = chart.options,
2744                  animationOpts = opts.animation,
2745                  arcOpts = opts.elements.arc,
2746                  centerX = (chartArea.left + chartArea.right) / 2,
2747                  centerY = (chartArea.top + chartArea.bottom) / 2,
2748                  startAngle = opts.rotation, // non reset case handled later
2749                  endAngle = opts.rotation, // non reset case handled later
2750                  dataset = me.getDataset(),
2751                  circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)),
2752                  innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius,
2753                  outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius,
2754                  custom = arc.custom || {},
2755                  valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
2756  
2757              helpers.extend(arc, {
2758                  // Utility

2759                  _datasetIndex: me.index,
2760                  _index: index,
2761  
2762                  // Desired view properties

2763                  _model: {
2764                      x: centerX + chart.offsetX,
2765                      y: centerY + chart.offsetY,
2766                      startAngle: startAngle,
2767                      endAngle: endAngle,
2768                      circumference: circumference,
2769                      outerRadius: outerRadius,
2770                      innerRadius: innerRadius,
2771                      label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
2772                  }
2773              });
2774  
2775              var model = arc._model;
2776              // Resets the visual styles

2777              this.removeHoverStyle(arc);
2778  
2779              // Set correct angles if not resetting

2780              if (!reset || !animationOpts.animateRotate) {
2781                  if (index === 0) {
2782                      model.startAngle = opts.rotation;
2783                  } else {
2784                      model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
2785                  }
2786  
2787                  model.endAngle = model.startAngle + model.circumference;
2788              }
2789  
2790              arc.pivot();
2791          },
2792  
2793          removeHoverStyle: function(arc) {
2794              Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
2795          },
2796  
2797          calculateTotal: function() {
2798              var dataset = this.getDataset();
2799              var meta = this.getMeta();
2800              var total = 0;
2801              var value;
2802  
2803              helpers.each(meta.data, function(element, index) {
2804                  value = dataset.data[index];
2805                  if (!isNaN(value) && !element.hidden) {
2806                      total += Math.abs(value);
2807                  }
2808              });
2809  
2810              return total;
2811          },
2812  
2813          calculateCircumference: function(value) {
2814              var total = this.getMeta().total;
2815              if (total > 0 && !isNaN(value)) {
2816                  return (Math.PI * 2.0) * (value / total);
2817              } else {
2818                  return 0;
2819              }
2820          }
2821      });
2822  };
2823  
2824  },{}],18:[function(require,module,exports){
2825  "use strict";
2826  
2827  module.exports = function(Chart) {
2828  
2829      var helpers = Chart.helpers;
2830  
2831      Chart.defaults.line = {
2832          showLines: true,
2833  
2834          hover: {
2835              mode: "label"
2836          },
2837  
2838          scales: {
2839              xAxes: [{
2840                  type: "category",
2841                  id: 'x-axis-0'
2842              }],
2843              yAxes: [{
2844                  type: "linear",
2845                  id: 'y-axis-0'
2846              }]
2847          }
2848      };
2849  
2850  	function lineEnabled(dataset, options) {
2851          return helpers.getValueOrDefault(dataset.showLine, options.showLines);
2852      }
2853  
2854      Chart.controllers.line = Chart.DatasetController.extend({
2855  
2856          datasetElementType: Chart.elements.Line,
2857  
2858          dataElementType: Chart.elements.Point,
2859  
2860          addElementAndReset: function(index) {
2861              var me = this;
2862              var options = me.chart.options;
2863              var meta = me.getMeta();
2864  
2865              Chart.DatasetController.prototype.addElementAndReset.call(me, index);
2866  
2867              // Make sure bezier control points are updated

2868              if (lineEnabled(me.getDataset(), options) && meta.dataset._model.tension !== 0) {
2869                  me.updateBezierControlPoints();
2870              }
2871          },
2872  
2873          update: function update(reset) {
2874              var me = this;
2875              var meta = me.getMeta();
2876              var line = meta.dataset;
2877              var points = meta.data || [];
2878              var options = me.chart.options;
2879              var lineElementOptions = options.elements.line;
2880              var scale = me.getScaleForId(meta.yAxisID);
2881              var i, ilen, custom;
2882              var dataset = me.getDataset();
2883              var showLine = lineEnabled(dataset, options);
2884  
2885              // Update Line

2886              if (showLine) {
2887                  custom = line.custom || {};
2888  
2889                  // Compatibility: If the properties are defined with only the old name, use those values

2890                  if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
2891                      dataset.lineTension = dataset.tension;
2892                  }
2893  
2894                  // Utility

2895                  line._scale = scale;
2896                  line._datasetIndex = me.index;
2897                  // Data

2898                  line._children = points;
2899                  // Model

2900                  line._model = {
2901                      // Appearance

2902                      // The default behavior of lines is to break at null values, according

2903                      // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158

2904                      // This option gives linse the ability to span gaps

2905                      spanGaps: dataset.spanGaps ? dataset.spanGaps : false,
2906                      tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
2907                      backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
2908                      borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
2909                      borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
2910                      borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
2911                      borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
2912                      borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
2913                      borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
2914                      fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
2915                      // Scale

2916                      scaleTop: scale.top,
2917                      scaleBottom: scale.bottom,
2918                      scaleZero: scale.getBasePixel()
2919                  };
2920  
2921                  line.pivot();
2922              }
2923  
2924              // Update Points

2925              for (i=0, ilen=points.length; i<ilen; ++i) {
2926                  me.updateElement(points[i], i, reset);
2927              }
2928  
2929              if (showLine && line._model.tension !== 0) {
2930                  me.updateBezierControlPoints();
2931              }
2932  
2933              // Now pivot the point for animation

2934              for (i=0, ilen=points.length; i<ilen; ++i) {
2935                  points[i].pivot();
2936              }
2937          },
2938  
2939          getPointBackgroundColor: function(point, index) {
2940              var backgroundColor = this.chart.options.elements.point.backgroundColor;
2941              var dataset = this.getDataset();
2942              var custom = point.custom || {};
2943  
2944              if (custom.backgroundColor) {
2945                  backgroundColor = custom.backgroundColor;
2946              } else if (dataset.pointBackgroundColor) {
2947                  backgroundColor = helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
2948              } else if (dataset.backgroundColor) {
2949                  backgroundColor = dataset.backgroundColor;
2950              }
2951  
2952              return backgroundColor;
2953          },
2954  
2955          getPointBorderColor: function(point, index) {
2956              var borderColor = this.chart.options.elements.point.borderColor;
2957              var dataset = this.getDataset();
2958              var custom = point.custom || {};
2959  
2960              if (custom.borderColor) {
2961                  borderColor = custom.borderColor;
2962              } else if (dataset.pointBorderColor) {
2963                  borderColor = helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
2964              } else if (dataset.borderColor) {
2965                  borderColor = dataset.borderColor;
2966              }
2967  
2968              return borderColor;
2969          },
2970  
2971          getPointBorderWidth: function(point, index) {
2972              var borderWidth = this.chart.options.elements.point.borderWidth;
2973              var dataset = this.getDataset();
2974              var custom = point.custom || {};
2975  
2976              if (custom.borderWidth) {
2977                  borderWidth = custom.borderWidth;
2978              } else if (dataset.pointBorderWidth) {
2979                  borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
2980              } else if (dataset.borderWidth) {
2981                  borderWidth = dataset.borderWidth;
2982              }
2983  
2984              return borderWidth;
2985          },
2986  
2987          updateElement: function(point, index, reset) {
2988              var me = this;
2989              var meta = me.getMeta();
2990              var custom = point.custom || {};
2991              var dataset = me.getDataset();
2992              var datasetIndex = me.index;
2993              var value = dataset.data[index];
2994              var yScale = me.getScaleForId(meta.yAxisID);
2995              var xScale = me.getScaleForId(meta.xAxisID);
2996              var pointOptions = me.chart.options.elements.point;
2997              var x, y;
2998  
2999              // Compatibility: If the properties are defined with only the old name, use those values

3000              if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
3001                  dataset.pointRadius = dataset.radius;
3002              }
3003              if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
3004                  dataset.pointHitRadius = dataset.hitRadius;
3005              }
3006  
3007              x = xScale.getPixelForValue(value, index, datasetIndex, me.chart.isCombo);
3008              y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex, me.chart.isCombo);
3009  
3010              // Utility

3011              point._xScale = xScale;
3012              point._yScale = yScale;
3013              point._datasetIndex = datasetIndex;
3014              point._index = index;
3015  
3016              // Desired view properties

3017              point._model = {
3018                  x: x,
3019                  y: y,
3020                  skip: custom.skip || isNaN(x) || isNaN(y),
3021                  // Appearance

3022                  radius: custom.radius || helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
3023                  pointStyle: custom.pointStyle || helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
3024                  backgroundColor: me.getPointBackgroundColor(point, index),
3025                  borderColor: me.getPointBorderColor(point, index),
3026                  borderWidth: me.getPointBorderWidth(point, index),
3027                  tension: meta.dataset._model ? meta.dataset._model.tension : 0,
3028                  // Tooltip

3029                  hitRadius: custom.hitRadius || helpers.getValueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
3030              };
3031          },
3032  
3033          calculatePointY: function(value, index, datasetIndex, isCombo) {
3034              var me = this;
3035              var chart = me.chart;
3036              var meta = me.getMeta();
3037              var yScale = me.getScaleForId(meta.yAxisID);
3038              var sumPos = 0;
3039              var sumNeg = 0;
3040              var i, ds, dsMeta;
3041  
3042              if (yScale.options.stacked) {
3043                  for (i = 0; i < datasetIndex; i++) {
3044                      ds = chart.data.datasets[i];
3045                      dsMeta = chart.getDatasetMeta(i);
3046                      if (dsMeta.type === 'line' && chart.isDatasetVisible(i)) {
3047                          if (ds.data[index] < 0) {
3048                              sumNeg += ds.data[index] || 0;
3049                          } else {
3050                              sumPos += ds.data[index] || 0;
3051                          }
3052                      }
3053                  }
3054  
3055                  if (value < 0) {
3056                      return yScale.getPixelForValue(sumNeg + value);
3057                  } else {
3058                      return yScale.getPixelForValue(sumPos + value);
3059                  }
3060              }
3061  
3062              return yScale.getPixelForValue(value);
3063          },
3064  
3065          updateBezierControlPoints: function() {
3066              var meta = this.getMeta();
3067              var area = this.chart.chartArea;
3068              var points = meta.data || [];
3069              var i, ilen, point, model, controlPoints;
3070  
3071              for (i=0, ilen=points.length; i<ilen; ++i) {
3072                  point = points[i];
3073                  model = point._model;
3074                  controlPoints = helpers.splineCurve(
3075                      helpers.previousItem(points, i)._model,
3076                      model,
3077                      helpers.nextItem(points, i)._model,
3078                      meta.dataset._model.tension
3079                  );
3080  
3081                  model.controlPointPreviousX = controlPoints.previous.x;
3082                  model.controlPointPreviousY = controlPoints.previous.y;
3083                  model.controlPointNextX = controlPoints.next.x;
3084                  model.controlPointNextY = controlPoints.next.y;
3085              }
3086          },
3087  
3088          draw: function(ease) {
3089              var me = this;
3090              var meta = me.getMeta();
3091              var points = meta.data || [];
3092              var easingDecimal = ease || 1;
3093              var i, ilen;
3094  
3095              // Transition Point Locations

3096              for (i=0, ilen=points.length; i<ilen; ++i) {
3097                  points[i].transition(easingDecimal);
3098              }
3099  
3100              // Transition and Draw the line

3101              if (lineEnabled(me.getDataset(), me.chart.options)) {
3102                  meta.dataset.transition(easingDecimal).draw();
3103              }
3104  
3105              // Draw the points

3106              for (i=0, ilen=points.length; i<ilen; ++i) {
3107                  points[i].draw();
3108              }
3109          },
3110  
3111          setHoverStyle: function(point) {
3112              // Point

3113              var dataset = this.chart.data.datasets[point._datasetIndex];
3114              var index = point._index;
3115              var custom = point.custom || {};
3116              var model = point._model;
3117  
3118              model.radius = custom.hoverRadius || helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
3119              model.backgroundColor = custom.hoverBackgroundColor || helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
3120              model.borderColor = custom.hoverBorderColor || helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
3121              model.borderWidth = custom.hoverBorderWidth || helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
3122          },
3123  
3124          removeHoverStyle: function(point) {
3125              var me = this;
3126              var dataset = me.chart.data.datasets[point._datasetIndex];
3127              var index = point._index;
3128              var custom = point.custom || {};
3129              var model = point._model;
3130  
3131              // Compatibility: If the properties are defined with only the old name, use those values

3132              if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
3133                  dataset.pointRadius = dataset.radius;
3134              }
3135  
3136              model.radius = custom.radius || helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius);
3137              model.backgroundColor = me.getPointBackgroundColor(point, index);
3138              model.borderColor = me.getPointBorderColor(point, index);
3139              model.borderWidth = me.getPointBorderWidth(point, index);
3140          }
3141      });
3142  };
3143  
3144  },{}],19:[function(require,module,exports){
3145  "use strict";
3146  
3147  module.exports = function(Chart) {
3148  
3149      var helpers = Chart.helpers;
3150  
3151      Chart.defaults.polarArea = {
3152  
3153          scale: {
3154              type: "radialLinear",
3155              lineArc: true // so that lines are circular
3156          },
3157  
3158          //Boolean - Whether to animate the rotation of the chart

3159          animation: {
3160              animateRotate: true,
3161              animateScale: true
3162          },
3163  
3164          aspectRatio: 1,
3165          legendCallback: function(chart) {
3166              var text = [];
3167              text.push('<ul class="' + chart.id + '-legend">');
3168  
3169              var data = chart.data;
3170              var datasets = data.datasets;
3171              var labels = data.labels;
3172  
3173              if (datasets.length) {
3174                  for (var i = 0; i < datasets[0].data.length; ++i) {
3175                      text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '">');
3176                      if (labels[i]) {
3177                          text.push(labels[i]);
3178                      }
3179                      text.push('</span></li>');
3180                  }
3181              }
3182  
3183              text.push('</ul>');
3184              return text.join("");
3185          },
3186          legend: {
3187              labels: {
3188                  generateLabels: function(chart) {
3189                      var data = chart.data;
3190                      if (data.labels.length && data.datasets.length) {
3191                          return data.labels.map(function(label, i) {
3192                              var meta = chart.getDatasetMeta(0);
3193                              var ds = data.datasets[0];
3194                              var arc = meta.data[i];
3195                              var custom = arc.custom || {};
3196                              var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
3197                              var arcOpts = chart.options.elements.arc;
3198                              var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
3199                              var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
3200                              var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
3201  
3202                              return {
3203                                  text: label,
3204                                  fillStyle: fill,
3205                                  strokeStyle: stroke,
3206                                  lineWidth: bw,
3207                                  hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
3208  
3209                                  // Extra data used for toggling the correct item

3210                                  index: i
3211                              };
3212                          });
3213                      } else {
3214                          return [];
3215                      }
3216                  }
3217              },
3218  
3219              onClick: function(e, legendItem) {
3220                  var index = legendItem.index;
3221                  var chart = this.chart;
3222                  var i, ilen, meta;
3223  
3224                  for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
3225                      meta = chart.getDatasetMeta(i);
3226                      meta.data[index].hidden = !meta.data[index].hidden;
3227                  }
3228  
3229                  chart.update();
3230              }
3231          },
3232  
3233          // Need to override these to give a nice default

3234          tooltips: {
3235              callbacks: {
3236                  title: function() {
3237                      return '';
3238                  },
3239                  label: function(tooltipItem, data) {
3240                      return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
3241                  }
3242              }
3243          }
3244      };
3245  
3246      Chart.controllers.polarArea = Chart.DatasetController.extend({
3247  
3248          dataElementType: Chart.elements.Arc,
3249  
3250          linkScales: helpers.noop,
3251  
3252          update: function update(reset) {
3253              var me = this;
3254              var chart = me.chart;
3255              var chartArea = chart.chartArea;
3256              var meta = me.getMeta();
3257              var opts = chart.options;
3258              var arcOpts = opts.elements.arc;
3259              var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
3260              chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
3261              chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
3262              chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
3263  
3264              me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
3265              me.innerRadius = me.outerRadius - chart.radiusLength;
3266  
3267              meta.count = me.countVisibleElements();
3268  
3269              helpers.each(meta.data, function(arc, index) {
3270                  me.updateElement(arc, index, reset);
3271              });
3272          },
3273  
3274          updateElement: function(arc, index, reset) {
3275              var me = this;
3276              var chart = me.chart;
3277              var chartArea = chart.chartArea;
3278              var dataset = me.getDataset();
3279              var opts = chart.options;
3280              var animationOpts = opts.animation;
3281              var arcOpts = opts.elements.arc;
3282              var custom = arc.custom || {};
3283              var scale = chart.scale;
3284              var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
3285              var labels = chart.data.labels;
3286  
3287              var circumference = me.calculateCircumference(dataset.data[index]);
3288              var centerX = (chartArea.left + chartArea.right) / 2;
3289              var centerY = (chartArea.top + chartArea.bottom) / 2;
3290  
3291              // If there is NaN data before us, we need to calculate the starting angle correctly.

3292              // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data

3293              var visibleCount = 0;
3294              var meta = me.getMeta();
3295              for (var i = 0; i < index; ++i) {
3296                  if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
3297                      ++visibleCount;
3298                  }
3299              }
3300  
3301              var negHalfPI = -0.5 * Math.PI;
3302              var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
3303              var startAngle = (negHalfPI) + (circumference * visibleCount);
3304              var endAngle = startAngle + (arc.hidden ? 0 : circumference);
3305  
3306              var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
3307  
3308              helpers.extend(arc, {
3309                  // Utility

3310                  _datasetIndex: me.index,
3311                  _index: index,
3312                  _scale: scale,
3313  
3314                  // Desired view properties

3315                  _model: {
3316                      x: centerX,
3317                      y: centerY,
3318                      innerRadius: 0,
3319                      outerRadius: reset ? resetRadius : distance,
3320                      startAngle: reset && animationOpts.animateRotate ? negHalfPI : startAngle,
3321                      endAngle: reset && animationOpts.animateRotate ? negHalfPI : endAngle,
3322                      label: getValueAtIndexOrDefault(labels, index, labels[index])
3323                  }
3324              });
3325  
3326              // Apply border and fill style

3327              me.removeHoverStyle(arc);
3328  
3329              arc.pivot();
3330          },
3331  
3332          removeHoverStyle: function(arc) {
3333              Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
3334          },
3335  
3336          countVisibleElements: function() {
3337              var dataset = this.getDataset();
3338              var meta = this.getMeta();
3339              var count = 0;
3340  
3341              helpers.each(meta.data, function(element, index) {
3342                  if (!isNaN(dataset.data[index]) && !element.hidden) {
3343                      count++;
3344                  }
3345              });
3346  
3347              return count;
3348          },
3349  
3350          calculateCircumference: function(value) {
3351              var count = this.getMeta().count;
3352              if (count > 0 && !isNaN(value)) {
3353                  return (2 * Math.PI) / count;
3354              } else {
3355                  return 0;
3356              }
3357          }
3358      });
3359  };
3360  
3361  },{}],20:[function(require,module,exports){
3362  "use strict";
3363  
3364  module.exports = function(Chart) {
3365  
3366      var helpers = Chart.helpers;
3367  
3368      Chart.defaults.radar = {
3369          scale: {
3370              type: "radialLinear"
3371          },
3372          elements: {
3373              line: {
3374                  tension: 0 // no bezier in radar
3375              }
3376          }
3377      };
3378  
3379      Chart.controllers.radar = Chart.DatasetController.extend({
3380  
3381          datasetElementType: Chart.elements.Line,
3382  
3383          dataElementType: Chart.elements.Point,
3384  
3385          linkScales: helpers.noop,
3386  
3387          addElementAndReset: function(index) {
3388              Chart.DatasetController.prototype.addElementAndReset.call(this, index);
3389  
3390              // Make sure bezier control points are updated

3391              this.updateBezierControlPoints();
3392          },
3393  
3394          update: function update(reset) {
3395              var me = this;
3396              var meta = me.getMeta();
3397              var line = meta.dataset;
3398              var points = meta.data;
3399              var custom = line.custom || {};
3400              var dataset = me.getDataset();
3401              var lineElementOptions = me.chart.options.elements.line;
3402              var scale = me.chart.scale;
3403  
3404              // Compatibility: If the properties are defined with only the old name, use those values

3405              if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
3406                  dataset.lineTension = dataset.tension;
3407              }
3408  
3409              helpers.extend(meta.dataset, {
3410                  // Utility

3411                  _datasetIndex: me.index,
3412                  // Data

3413                  _children: points,
3414                  _loop: true,
3415                  // Model

3416                  _model: {
3417                      // Appearance

3418                      tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
3419                      backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
3420                      borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
3421                      borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
3422                      fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
3423                      borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
3424                      borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
3425                      borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
3426                      borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
3427  
3428                      // Scale

3429                      scaleTop: scale.top,
3430                      scaleBottom: scale.bottom,
3431                      scaleZero: scale.getBasePosition()
3432                  }
3433              });
3434  
3435              meta.dataset.pivot();
3436  
3437              // Update Points

3438              helpers.each(points, function(point, index) {
3439                  me.updateElement(point, index, reset);
3440              }, me);
3441  
3442  
3443              // Update bezier control points

3444              me.updateBezierControlPoints();
3445          },
3446          updateElement: function(point, index, reset) {
3447              var me = this;
3448              var custom = point.custom || {};
3449              var dataset = me.getDataset();
3450              var scale = me.chart.scale;
3451              var pointElementOptions = me.chart.options.elements.point;
3452              var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
3453  
3454              helpers.extend(point, {
3455                  // Utility

3456                  _datasetIndex: me.index,
3457                  _index: index,
3458                  _scale: scale,
3459  
3460                  // Desired view properties

3461                  _model: {
3462                      x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
3463                      y: reset ? scale.yCenter : pointPosition.y,
3464  
3465                      // Appearance

3466                      tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.tension, me.chart.options.elements.line.tension),
3467                      radius: custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
3468                      backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
3469                      borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
3470                      borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
3471                      pointStyle: custom.pointStyle ? custom.pointStyle : helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
3472  
3473                      // Tooltip

3474                      hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius)
3475                  }
3476              });
3477  
3478              point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
3479          },
3480          updateBezierControlPoints: function() {
3481              var chartArea = this.chart.chartArea;
3482              var meta = this.getMeta();
3483  
3484              helpers.each(meta.data, function(point, index) {
3485                  var model = point._model;
3486                  var controlPoints = helpers.splineCurve(
3487                      helpers.previousItem(meta.data, index, true)._model,
3488                      model,
3489                      helpers.nextItem(meta.data, index, true)._model,
3490                      model.tension
3491                  );
3492  
3493                  // Prevent the bezier going outside of the bounds of the graph

3494                  model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
3495                  model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);
3496  
3497                  model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
3498                  model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);
3499  
3500                  // Now pivot the point for animation

3501                  point.pivot();
3502              });
3503          },
3504  
3505          draw: function(ease) {
3506              var meta = this.getMeta();
3507              var easingDecimal = ease || 1;
3508  
3509              // Transition Point Locations

3510              helpers.each(meta.data, function(point, index) {
3511                  point.transition(easingDecimal);
3512              });
3513  
3514              // Transition and Draw the line

3515              meta.dataset.transition(easingDecimal).draw();
3516  
3517              // Draw the points

3518              helpers.each(meta.data, function(point) {
3519                  point.draw();
3520              });
3521          },
3522  
3523          setHoverStyle: function(point) {
3524              // Point

3525              var dataset = this.chart.data.datasets[point._datasetIndex];
3526              var custom = point.custom || {};
3527              var index = point._index;
3528              var model = point._model;
3529  
3530              model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
3531              model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
3532              model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
3533              model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
3534          },
3535  
3536          removeHoverStyle: function(point) {
3537              var dataset = this.chart.data.datasets[point._datasetIndex];
3538              var custom = point.custom || {};
3539              var index = point._index;
3540              var model = point._model;
3541              var pointElementOptions = this.chart.options.elements.point;
3542  
3543              model.radius = custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.radius, index, pointElementOptions.radius);
3544              model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor);
3545              model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor);
3546              model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth);
3547          }
3548      });
3549  };
3550  
3551  },{}],21:[function(require,module,exports){
3552  /*global window: false */

3553  "use strict";
3554  
3555  module.exports = function(Chart) {
3556  
3557      var helpers = Chart.helpers;
3558  
3559      Chart.defaults.global.animation = {
3560          duration: 1000,
3561          easing: "easeOutQuart",
3562          onProgress: helpers.noop,
3563          onComplete: helpers.noop
3564      };
3565  
3566      Chart.Animation = Chart.Element.extend({
3567          currentStep: null, // the current animation step
3568          numSteps: 60, // default number of steps
3569          easing: "", // the easing to use for this animation
3570          render: null, // render function used by the animation service
3571  
3572          onAnimationProgress: null, // user specified callback to fire on each step of the animation
3573          onAnimationComplete: null // user specified callback to fire when the animation finishes
3574      });
3575  
3576      Chart.animationService = {
3577          frameDuration: 17,
3578          animations: [],
3579          dropFrames: 0,
3580          request: null,
3581          addAnimation: function(chartInstance, animationObject, duration, lazy) {
3582              var me = this;
3583  
3584              if (!lazy) {
3585                  chartInstance.animating = true;
3586              }
3587  
3588              for (var index = 0; index < me.animations.length; ++index) {
3589                  if (me.animations[index].chartInstance === chartInstance) {
3590                      // replacing an in progress animation

3591                      me.animations[index].animationObject = animationObject;
3592                      return;
3593                  }
3594              }
3595  
3596              me.animations.push({
3597                  chartInstance: chartInstance,
3598                  animationObject: animationObject
3599              });
3600  
3601              // If there are no animations queued, manually kickstart a digest, for lack of a better word

3602              if (me.animations.length === 1) {
3603                  me.requestAnimationFrame();
3604              }
3605          },
3606          // Cancel the animation for a given chart instance

3607          cancelAnimation: function(chartInstance) {
3608              var index = helpers.findIndex(this.animations, function(animationWrapper) {
3609                  return animationWrapper.chartInstance === chartInstance;
3610              });
3611  
3612              if (index !== -1) {
3613                  this.animations.splice(index, 1);
3614                  chartInstance.animating = false;
3615              }
3616          },
3617          requestAnimationFrame: function() {
3618              var me = this;
3619              if (me.request === null) {
3620                  // Skip animation frame requests until the active one is executed.

3621                  // This can happen when processing mouse events, e.g. 'mousemove'

3622                  // and 'mouseout' events will trigger multiple renders.

3623                  me.request = helpers.requestAnimFrame.call(window, function() {
3624                      me.request = null;
3625                      me.startDigest();
3626                  });
3627              }
3628          },
3629          startDigest: function() {
3630              var me = this;
3631  
3632              var startTime = Date.now();
3633              var framesToDrop = 0;
3634  
3635              if (me.dropFrames > 1) {
3636                  framesToDrop = Math.floor(me.dropFrames);
3637                  me.dropFrames = me.dropFrames % 1;
3638              }
3639  
3640              var i = 0;
3641              while (i < me.animations.length) {
3642                  if (me.animations[i].animationObject.currentStep === null) {
3643                      me.animations[i].animationObject.currentStep = 0;
3644                  }
3645  
3646                  me.animations[i].animationObject.currentStep += 1 + framesToDrop;
3647  
3648                  if (me.animations[i].animationObject.currentStep > me.animations[i].animationObject.numSteps) {
3649                      me.animations[i].animationObject.currentStep = me.animations[i].animationObject.numSteps;
3650                  }
3651  
3652                  me.animations[i].animationObject.render(me.animations[i].chartInstance, me.animations[i].animationObject);
3653                  if (me.animations[i].animationObject.onAnimationProgress && me.animations[i].animationObject.onAnimationProgress.call) {
3654                      me.animations[i].animationObject.onAnimationProgress.call(me.animations[i].chartInstance, me.animations[i]);
3655                  }
3656  
3657                  if (me.animations[i].animationObject.currentStep === me.animations[i].animationObject.numSteps) {
3658                      if (me.animations[i].animationObject.onAnimationComplete && me.animations[i].animationObject.onAnimationComplete.call) {
3659                          me.animations[i].animationObject.onAnimationComplete.call(me.animations[i].chartInstance, me.animations[i]);
3660                      }
3661  
3662                      // executed the last frame. Remove the animation.

3663                      me.animations[i].chartInstance.animating = false;
3664  
3665                      me.animations.splice(i, 1);
3666                  } else {
3667                      ++i;
3668                  }
3669              }
3670  
3671              var endTime = Date.now();
3672              var dropFrames = (endTime - startTime) / me.frameDuration;
3673  
3674              me.dropFrames += dropFrames;
3675  
3676              // Do we have more stuff to animate?

3677              if (me.animations.length > 0) {
3678                  me.requestAnimationFrame();
3679              }
3680          }
3681      };
3682  };
3683  },{}],22:[function(require,module,exports){
3684  "use strict";
3685  
3686  module.exports = function(Chart) {
3687  
3688      var helpers = Chart.helpers;
3689      //Create a dictionary of chart types, to allow for extension of existing types

3690      Chart.types = {};
3691  
3692      //Store a reference to each instance - allowing us to globally resize chart instances on window resize.

3693      //Destroy method on the chart will remove the instance of the chart from this reference.

3694      Chart.instances = {};
3695  
3696      // Controllers available for dataset visualization eg. bar, line, slice, etc.

3697      Chart.controllers = {};
3698  
3699      /**

3700       * @class Chart.Controller

3701       * The main controller of a chart.

3702       */
3703      Chart.Controller = function(instance) {
3704  
3705          this.chart = instance;
3706          this.config = instance.config;
3707          this.options = this.config.options = helpers.configMerge(Chart.defaults.global, Chart.defaults[this.config.type], this.config.options || {});
3708          this.id = helpers.uid();
3709  
3710          Object.defineProperty(this, 'data', {
3711              get: function() {
3712                  return this.config.data;
3713              }
3714          });
3715  
3716          //Add the chart instance to the global namespace

3717          Chart.instances[this.id] = this;
3718  
3719          if (this.options.responsive) {
3720              // Silent resize before chart draws

3721              this.resize(true);
3722          }
3723  
3724          this.initialize();
3725  
3726          return this;
3727      };
3728  
3729      helpers.extend(Chart.Controller.prototype, /** @lends Chart.Controller */ {
3730  
3731          initialize: function initialize() {
3732              var me = this;
3733              // Before init plugin notification

3734              Chart.plugins.notify('beforeInit', [me]);
3735  
3736              me.bindEvents();
3737  
3738              // Make sure controllers are built first so that each dataset is bound to an axis before the scales

3739              // are built

3740              me.ensureScalesHaveIDs();
3741              me.buildOrUpdateControllers();
3742              me.buildScales();
3743              me.updateLayout();
3744              me.resetElements();
3745              me.initToolTip();
3746              me.update();
3747  
3748              // After init plugin notification

3749              Chart.plugins.notify('afterInit', [me]);
3750  
3751              return me;
3752          },
3753  
3754          clear: function clear() {
3755              helpers.clear(this.chart);
3756              return this;
3757          },
3758  
3759          stop: function stop() {
3760              // Stops any current animation loop occuring

3761              Chart.animationService.cancelAnimation(this);
3762              return this;
3763          },
3764  
3765          resize: function resize(silent) {
3766              var me = this;
3767              var chart = me.chart;
3768              var canvas = chart.canvas;
3769              var newWidth = helpers.getMaximumWidth(canvas);
3770              var aspectRatio = chart.aspectRatio;
3771              var newHeight = (me.options.maintainAspectRatio && isNaN(aspectRatio) === false && isFinite(aspectRatio) && aspectRatio !== 0) ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas);
3772  
3773              var sizeChanged = chart.width !== newWidth || chart.height !== newHeight;
3774  
3775              if (!sizeChanged) {
3776                  return me;
3777              }
3778  
3779              canvas.width = chart.width = newWidth;
3780              canvas.height = chart.height = newHeight;
3781  
3782              helpers.retinaScale(chart);
3783  
3784              // Notify any plugins about the resize

3785              var newSize = { width: newWidth, height: newHeight };
3786              Chart.plugins.notify('resize', [me, newSize]);
3787  
3788              // Notify of resize

3789              if (me.options.onResize) {
3790                  me.options.onResize(me, newSize);
3791              }
3792  
3793              if (!silent) {
3794                  me.stop();
3795                  me.update(me.options.responsiveAnimationDuration);
3796              }
3797  
3798              return me;
3799          },
3800  
3801          ensureScalesHaveIDs: function ensureScalesHaveIDs() {
3802              var options = this.options;
3803              var scalesOptions = options.scales || {};
3804              var scaleOptions = options.scale;
3805  
3806              helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) {
3807                  xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
3808              });
3809  
3810              helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) {
3811                  yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
3812              });
3813  
3814              if (scaleOptions) {
3815                  scaleOptions.id = scaleOptions.id || 'scale';
3816              }
3817          },
3818  
3819          /**

3820           * Builds a map of scale ID to scale object for future lookup.

3821           */
3822          buildScales: function buildScales() {
3823              var me = this;
3824              var options = me.options;
3825              var scales = me.scales = {};
3826              var items = [];
3827  
3828              if (options.scales) {
3829                  items = items.concat(
3830                      (options.scales.xAxes || []).map(function(xAxisOptions) {
3831                          return { options: xAxisOptions, dtype: 'category' }; }),
3832                      (options.scales.yAxes || []).map(function(yAxisOptions) {
3833                          return { options: yAxisOptions, dtype: 'linear' }; }));
3834              }
3835  
3836              if (options.scale) {
3837                  items.push({ options: options.scale, dtype: 'radialLinear', isDefault: true });
3838              }
3839  
3840              helpers.each(items, function(item, index) {
3841                  var scaleOptions = item.options;
3842                  var scaleType = helpers.getValueOrDefault(scaleOptions.type, item.dtype);
3843                  var scaleClass = Chart.scaleService.getScaleConstructor(scaleType);
3844                  if (!scaleClass) {
3845                      return;
3846                  }
3847  
3848                  var scale = new scaleClass({
3849                      id: scaleOptions.id,
3850                      options: scaleOptions,
3851                      ctx: me.chart.ctx,
3852                      chart: me
3853                  });
3854  
3855                  scales[scale.id] = scale;
3856  
3857                  // TODO(SB): I think we should be able to remove this custom case (options.scale)

3858                  // and consider it as a regular scale part of the "scales"" map only! This would

3859                  // make the logic easier and remove some useless? custom code.

3860                  if (item.isDefault) {
3861                      me.scale = scale;
3862                  }
3863              });
3864  
3865              Chart.scaleService.addScalesToLayout(this);
3866          },
3867  
3868          updateLayout: function() {
3869              Chart.layoutService.update(this, this.chart.width, this.chart.height);
3870          },
3871  
3872          buildOrUpdateControllers: function buildOrUpdateControllers() {
3873              var me = this;
3874              var types = [];
3875              var newControllers = [];
3876  
3877              helpers.each(me.data.datasets, function(dataset, datasetIndex) {
3878                  var meta = me.getDatasetMeta(datasetIndex);
3879                  if (!meta.type) {
3880                      meta.type = dataset.type || me.config.type;
3881                  }
3882  
3883                  types.push(meta.type);
3884  
3885                  if (meta.controller) {
3886                      meta.controller.updateIndex(datasetIndex);
3887                  } else {
3888                      meta.controller = new Chart.controllers[meta.type](me, datasetIndex);
3889                      newControllers.push(meta.controller);
3890                  }
3891              }, me);
3892  
3893              if (types.length > 1) {
3894                  for (var i = 1; i < types.length; i++) {
3895                      if (types[i] !== types[i - 1]) {
3896                          me.isCombo = true;
3897                          break;
3898                      }
3899                  }
3900              }
3901  
3902              return newControllers;
3903          },
3904  
3905          resetElements: function resetElements() {
3906              var me = this;
3907              helpers.each(me.data.datasets, function(dataset, datasetIndex) {
3908                  me.getDatasetMeta(datasetIndex).controller.reset();
3909              }, me);
3910          },
3911  
3912          update: function update(animationDuration, lazy) {
3913              var me = this;
3914              Chart.plugins.notify('beforeUpdate', [me]);
3915  
3916              // In case the entire data object changed

3917              me.tooltip._data = me.data;
3918  
3919              // Make sure dataset controllers are updated and new controllers are reset

3920              var newControllers = me.buildOrUpdateControllers();
3921  
3922              // Make sure all dataset controllers have correct meta data counts

3923              helpers.each(me.data.datasets, function(dataset, datasetIndex) {
3924                  me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
3925              }, me);
3926  
3927              Chart.layoutService.update(me, me.chart.width, me.chart.height);
3928  
3929              // Apply changes to the dataets that require the scales to have been calculated i.e BorderColor chages

3930              Chart.plugins.notify('afterScaleUpdate', [me]);
3931  
3932              // Can only reset the new controllers after the scales have been updated

3933              helpers.each(newControllers, function(controller) {
3934                  controller.reset();
3935              });
3936  
3937              me.updateDatasets();
3938  
3939              // Do this before render so that any plugins that need final scale updates can use it

3940              Chart.plugins.notify('afterUpdate', [me]);
3941  
3942              me.render(animationDuration, lazy);
3943          },
3944  
3945          /**

3946           * @method beforeDatasetsUpdate

3947           * @description Called before all datasets are updated. If a plugin returns false,

3948           * the datasets update will be cancelled until another chart update is triggered.

3949           * @param {Object} instance the chart instance being updated.

3950           * @returns {Boolean} false to cancel the datasets update.

3951           * @memberof Chart.PluginBase

3952           * @since version 2.1.5

3953           * @instance

3954           */
3955  
3956          /**

3957           * @method afterDatasetsUpdate

3958           * @description Called after all datasets have been updated. Note that this

3959           * extension will not be called if the datasets update has been cancelled.

3960           * @param {Object} instance the chart instance being updated.

3961           * @memberof Chart.PluginBase

3962           * @since version 2.1.5

3963           * @instance

3964           */
3965  
3966          /**

3967           * Updates all datasets unless a plugin returns false to the beforeDatasetsUpdate

3968           * extension, in which case no datasets will be updated and the afterDatasetsUpdate

3969           * notification will be skipped.

3970           * @protected

3971           * @instance

3972           */
3973          updateDatasets: function() {
3974              var me = this;
3975              var i, ilen;
3976  
3977              if (Chart.plugins.notify('beforeDatasetsUpdate', [ me ])) {
3978                  for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
3979                      me.getDatasetMeta(i).controller.update();
3980                  }
3981  
3982                  Chart.plugins.notify('afterDatasetsUpdate', [ me ]);
3983              }
3984          },
3985  
3986          render: function render(duration, lazy) {
3987              var me = this;
3988              Chart.plugins.notify('beforeRender', [me]);
3989  
3990              var animationOptions = me.options.animation;
3991              if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
3992                  var animation = new Chart.Animation();
3993                  animation.numSteps = (duration || animationOptions.duration) / 16.66; //60 fps

3994                  animation.easing = animationOptions.easing;
3995  
3996                  // render function

3997                  animation.render = function(chartInstance, animationObject) {
3998                      var easingFunction = helpers.easingEffects[animationObject.easing];
3999                      var stepDecimal = animationObject.currentStep / animationObject.numSteps;
4000                      var easeDecimal = easingFunction(stepDecimal);
4001  
4002                      chartInstance.draw(easeDecimal, stepDecimal, animationObject.currentStep);
4003                  };
4004  
4005                  // user events

4006                  animation.onAnimationProgress = animationOptions.onProgress;
4007                  animation.onAnimationComplete = animationOptions.onComplete;
4008  
4009                  Chart.animationService.addAnimation(me, animation, duration, lazy);
4010              } else {
4011                  me.draw();
4012                  if (animationOptions && animationOptions.onComplete && animationOptions.onComplete.call) {
4013                      animationOptions.onComplete.call(me);
4014                  }
4015              }
4016              return me;
4017          },
4018  
4019          draw: function(ease) {
4020              var me = this;
4021              var easingDecimal = ease || 1;
4022              me.clear();
4023  
4024              Chart.plugins.notify('beforeDraw', [me, easingDecimal]);
4025  
4026              // Draw all the scales

4027              helpers.each(me.boxes, function(box) {
4028                  box.draw(me.chartArea);
4029              }, me);
4030              if (me.scale) {
4031                  me.scale.draw();
4032              }
4033  
4034              Chart.plugins.notify('beforeDatasetsDraw', [me, easingDecimal]);
4035  
4036              // Draw each dataset via its respective controller (reversed to support proper line stacking)

4037              helpers.each(me.data.datasets, function(dataset, datasetIndex) {
4038                  if (me.isDatasetVisible(datasetIndex)) {
4039                      me.getDatasetMeta(datasetIndex).controller.draw(ease);
4040                  }
4041              }, me, true);
4042  
4043              Chart.plugins.notify('afterDatasetsDraw', [me, easingDecimal]);
4044  
4045              // Finally draw the tooltip

4046              me.tooltip.transition(easingDecimal).draw();
4047  
4048              Chart.plugins.notify('afterDraw', [me, easingDecimal]);
4049          },
4050  
4051          // Get the single element that was clicked on

4052          // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw

4053          getElementAtEvent: function(e) {
4054              var me = this;
4055              var eventPosition = helpers.getRelativePosition(e, me.chart);
4056              var elementsArray = [];
4057  
4058              helpers.each(me.data.datasets, function(dataset, datasetIndex) {
4059                  if (me.isDatasetVisible(datasetIndex)) {
4060                      var meta = me.getDatasetMeta(datasetIndex);
4061                      helpers.each(meta.data, function(element, index) {
4062                          if (element.inRange(eventPosition.x, eventPosition.y)) {
4063                              elementsArray.push(element);
4064                              return elementsArray;
4065                          }
4066                      });
4067                  }
4068              });
4069  
4070              return elementsArray;
4071          },
4072  
4073          getElementsAtEvent: function(e) {
4074              var me = this;
4075              var eventPosition = helpers.getRelativePosition(e, me.chart);
4076              var elementsArray = [];
4077  
4078              var found = (function() {
4079                  if (me.data.datasets) {
4080                      for (var i = 0; i < me.data.datasets.length; i++) {
4081                          var meta = me.getDatasetMeta(i);
4082                          if (me.isDatasetVisible(i)) {
4083                              for (var j = 0; j < meta.data.length; j++) {
4084                                  if (meta.data[j].inRange(eventPosition.x, eventPosition.y)) {
4085                                      return meta.data[j];
4086                                  }
4087                              }
4088                          }
4089                      }
4090                  }
4091              }).call(me);
4092  
4093              if (!found) {
4094                  return elementsArray;
4095              }
4096  
4097              helpers.each(me.data.datasets, function(dataset, datasetIndex) {
4098                  if (me.isDatasetVisible(datasetIndex)) {
4099                      var meta = me.getDatasetMeta(datasetIndex);
4100                      elementsArray.push(meta.data[found._index]);
4101                  }
4102              }, me);
4103  
4104              return elementsArray;
4105          },
4106  
4107          getElementsAtEventForMode: function(e, mode) {
4108              var me = this;
4109              switch (mode) {
4110              case 'single':
4111                  return me.getElementAtEvent(e);
4112              case 'label':
4113                  return me.getElementsAtEvent(e);
4114              case 'dataset':
4115                  return me.getDatasetAtEvent(e);
4116              default:
4117                  return e;
4118              }
4119          },
4120  
4121          getDatasetAtEvent: function(e) {
4122              var elementsArray = this.getElementAtEvent(e);
4123  
4124              if (elementsArray.length > 0) {
4125                  elementsArray = this.getDatasetMeta(elementsArray[0]._datasetIndex).data;
4126              }
4127  
4128              return elementsArray;
4129          },
4130  
4131          getDatasetMeta: function(datasetIndex) {
4132              var me = this;
4133              var dataset = me.data.datasets[datasetIndex];
4134              if (!dataset._meta) {
4135                  dataset._meta = {};
4136              }
4137  
4138              var meta = dataset._meta[me.id];
4139              if (!meta) {
4140                  meta = dataset._meta[me.id] = {
4141                  type: null,
4142                  data: [],
4143                  dataset: null,
4144                  controller: null,
4145                  hidden: null,            // See isDatasetVisible() comment
4146                  xAxisID: null,
4147                  yAxisID: null
4148              };
4149              }
4150  
4151              return meta;
4152          },
4153  
4154          getVisibleDatasetCount: function() {
4155              var count = 0;
4156              for (var i = 0, ilen = this.data.datasets.length; i<ilen; ++i) {
4157                   if (this.isDatasetVisible(i)) {
4158                      count++;
4159                  }
4160              }
4161              return count;
4162          },
4163  
4164          isDatasetVisible: function(datasetIndex) {
4165              var meta = this.getDatasetMeta(datasetIndex);
4166  
4167              // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,

4168              // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.

4169              return typeof meta.hidden === 'boolean'? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
4170          },
4171  
4172          generateLegend: function generateLegend() {
4173              return this.options.legendCallback(this);
4174          },
4175  
4176          destroy: function destroy() {
4177              var me = this;
4178              me.stop();
4179              me.clear();
4180              helpers.unbindEvents(me, me.events);
4181              helpers.removeResizeListener(me.chart.canvas.parentNode);
4182  
4183              // Reset canvas height/width attributes

4184              var canvas = me.chart.canvas;
4185              canvas.width = me.chart.width;
4186              canvas.height = me.chart.height;
4187  
4188              // if we scaled the canvas in response to a devicePixelRatio !== 1, we need to undo that transform here

4189              if (me.chart.originalDevicePixelRatio !== undefined) {
4190                  me.chart.ctx.scale(1 / me.chart.originalDevicePixelRatio, 1 / me.chart.originalDevicePixelRatio);
4191              }
4192  
4193              // Reset to the old style since it may have been changed by the device pixel ratio changes

4194              canvas.style.width = me.chart.originalCanvasStyleWidth;
4195              canvas.style.height = me.chart.originalCanvasStyleHeight;
4196  
4197              Chart.plugins.notify('destroy', [me]);
4198  
4199              delete Chart.instances[me.id];
4200          },
4201  
4202          toBase64Image: function toBase64Image() {
4203              return this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments);
4204          },
4205  
4206          initToolTip: function initToolTip() {
4207              var me = this;
4208              me.tooltip = new Chart.Tooltip({
4209                  _chart: me.chart,
4210                  _chartInstance: me,
4211                  _data: me.data,
4212                  _options: me.options.tooltips
4213              }, me);
4214          },
4215  
4216          bindEvents: function bindEvents() {
4217              var me = this;
4218              helpers.bindEvents(me, me.options.events, function(evt) {
4219                  me.eventHandler(evt);
4220              });
4221          },
4222  
4223          updateHoverStyle: function(elements, mode, enabled) {
4224              var method = enabled? 'setHoverStyle' : 'removeHoverStyle';
4225              var element, i, ilen;
4226  
4227              switch (mode) {
4228              case 'single':
4229                  elements = [ elements[0] ];
4230                  break;
4231              case 'label':
4232              case 'dataset':
4233                  // elements = elements;

4234                  break;
4235              default:
4236                  // unsupported mode

4237                  return;
4238              }
4239  
4240              for (i=0, ilen=elements.length; i<ilen; ++i) {
4241                  element = elements[i];
4242                  if (element) {
4243                      this.getDatasetMeta(element._datasetIndex).controller[method](element);
4244                  }
4245              }
4246          },
4247  
4248          eventHandler: function eventHandler(e) {
4249              var me = this;
4250              var tooltip = me.tooltip;
4251              var options = me.options || {};
4252              var hoverOptions = options.hover;
4253              var tooltipsOptions = options.tooltips;
4254  
4255              me.lastActive = me.lastActive || [];
4256              me.lastTooltipActive = me.lastTooltipActive || [];
4257  
4258              // Find Active Elements for hover and tooltips

4259              if (e.type === 'mouseout') {
4260                  me.active = [];
4261                  me.tooltipActive = [];
4262              } else {
4263                  me.active = me.getElementsAtEventForMode(e, hoverOptions.mode);
4264                  me.tooltipActive =  me.getElementsAtEventForMode(e, tooltipsOptions.mode);
4265              }
4266  
4267              // On Hover hook

4268              if (hoverOptions.onHover) {
4269                  hoverOptions.onHover.call(me, me.active);
4270              }
4271  
4272              if (e.type === 'mouseup' || e.type === 'click') {
4273                  if (options.onClick) {
4274                      options.onClick.call(me, e, me.active);
4275                  }
4276                  if (me.legend && me.legend.handleEvent) {
4277                      me.legend.handleEvent(e);
4278                  }
4279              }
4280  
4281              // Remove styling for last active (even if it may still be active)

4282              if (me.lastActive.length) {
4283                  me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
4284              }
4285  
4286              // Built in hover styling

4287              if (me.active.length && hoverOptions.mode) {
4288                  me.updateHoverStyle(me.active, hoverOptions.mode, true);
4289              }
4290  
4291              // Built in Tooltips

4292              if (tooltipsOptions.enabled || tooltipsOptions.custom) {
4293                  tooltip.initialize();
4294                  tooltip._active = me.tooltipActive;
4295                  tooltip.update(true);
4296              }
4297  
4298              // Hover animations

4299              tooltip.pivot();
4300  
4301              if (!me.animating) {
4302                  // If entering, leaving, or changing elements, animate the change via pivot

4303                  if (!helpers.arrayEquals(me.active, me.lastActive) ||
4304                      !helpers.arrayEquals(me.tooltipActive, me.lastTooltipActive)) {
4305  
4306                      me.stop();
4307  
4308                      if (tooltipsOptions.enabled || tooltipsOptions.custom) {
4309                          tooltip.update(true);
4310                      }
4311  
4312                      // We only need to render at this point. Updating will cause scales to be

4313                      // recomputed generating flicker & using more memory than necessary.

4314                      me.render(hoverOptions.animationDuration, true);
4315                  }
4316              }
4317  
4318              // Remember Last Actives

4319              me.lastActive = me.active;
4320              me.lastTooltipActive = me.tooltipActive;
4321              return me;
4322          }
4323      });
4324  };
4325  
4326  },{}],23:[function(require,module,exports){
4327  "use strict";
4328  
4329  module.exports = function(Chart) {
4330  
4331      var helpers = Chart.helpers;
4332      var noop = helpers.noop;
4333  
4334      // Base class for all dataset controllers (line, bar, etc)

4335      Chart.DatasetController = function(chart, datasetIndex) {
4336          this.initialize.call(this, chart, datasetIndex);
4337      };
4338  
4339      helpers.extend(Chart.DatasetController.prototype, {
4340  
4341          /**

4342           * Element type used to generate a meta dataset (e.g. Chart.element.Line).

4343           * @type {Chart.core.element}

4344           */
4345          datasetElementType: null,
4346  
4347          /**

4348           * Element type used to generate a meta data (e.g. Chart.element.Point).

4349           * @type {Chart.core.element}

4350           */
4351          dataElementType: null,
4352  
4353          initialize: function(chart, datasetIndex) {
4354              var me = this;
4355              me.chart = chart;
4356              me.index = datasetIndex;
4357              me.linkScales();
4358              me.addElements();
4359          },
4360  
4361          updateIndex: function(datasetIndex) {
4362              this.index = datasetIndex;
4363          },
4364  
4365          linkScales: function() {
4366              var me = this;
4367              var meta = me.getMeta();
4368              var dataset = me.getDataset();
4369  
4370              if (meta.xAxisID === null) {
4371                  meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
4372              }
4373              if (meta.yAxisID === null) {
4374                  meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
4375              }
4376          },
4377  
4378          getDataset: function() {
4379              return this.chart.data.datasets[this.index];
4380          },
4381  
4382          getMeta: function() {
4383              return this.chart.getDatasetMeta(this.index);
4384          },
4385  
4386          getScaleForId: function(scaleID) {
4387              return this.chart.scales[scaleID];
4388          },
4389  
4390          reset: function() {
4391              this.update(true);
4392          },
4393  
4394          createMetaDataset: function() {
4395              var me = this;
4396              var type = me.datasetElementType;
4397              return type && new type({
4398                  _chart: me.chart.chart,
4399                  _datasetIndex: me.index
4400              });
4401          },
4402  
4403          createMetaData: function(index) {
4404              var me = this;
4405              var type = me.dataElementType;
4406              return type && new type({
4407                  _chart: me.chart.chart,
4408                  _datasetIndex: me.index,
4409                  _index: index
4410              });
4411          },
4412  
4413          addElements: function() {
4414              var me = this;
4415              var meta = me.getMeta();
4416              var data = me.getDataset().data || [];
4417              var metaData = meta.data;
4418              var i, ilen;
4419  
4420              for (i=0, ilen=data.length; i<ilen; ++i) {
4421                  metaData[i] = metaData[i] || me.createMetaData(meta, i);
4422              }
4423  
4424              meta.dataset = meta.dataset || me.createMetaDataset();
4425          },
4426  
4427          addElementAndReset: function(index) {
4428              var me = this;
4429              var element = me.createMetaData(index);
4430              me.getMeta().data.splice(index, 0, element);
4431              me.updateElement(element, index, true);
4432          },
4433  
4434          buildOrUpdateElements: function buildOrUpdateElements() {
4435              // Handle the number of data points changing

4436              var meta = this.getMeta(),
4437                  md = meta.data,
4438                  numData = this.getDataset().data.length,
4439                  numMetaData = md.length;
4440  
4441              // Make sure that we handle number of datapoints changing

4442              if (numData < numMetaData) {
4443                  // Remove excess bars for data points that have been removed

4444                  md.splice(numData, numMetaData - numData);
4445              } else if (numData > numMetaData) {
4446                  // Add new elements

4447                  for (var index = numMetaData; index < numData; ++index) {
4448                      this.addElementAndReset(index);
4449                  }
4450              }
4451          },
4452  
4453          update: noop,
4454  
4455          draw: function(ease) {
4456              var easingDecimal = ease || 1;
4457              helpers.each(this.getMeta().data, function(element, index) {
4458                  element.transition(easingDecimal).draw();
4459              });
4460          },
4461  
4462          removeHoverStyle: function(element, elementOpts) {
4463              var dataset = this.chart.data.datasets[element._datasetIndex],
4464                  index = element._index,
4465                  custom = element.custom || {},
4466                  valueOrDefault = helpers.getValueAtIndexOrDefault,
4467                  color = helpers.color,
4468                  model = element._model;
4469  
4470              model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
4471              model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
4472              model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
4473          },
4474  
4475          setHoverStyle: function(element) {
4476              var dataset = this.chart.data.datasets[element._datasetIndex],
4477                  index = element._index,
4478                  custom = element.custom || {},
4479                  valueOrDefault = helpers.getValueAtIndexOrDefault,
4480                  color = helpers.color,
4481                  getHoverColor = helpers.getHoverColor,
4482                  model = element._model;
4483  
4484              model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
4485              model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
4486              model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
4487          }
4488      });
4489  
4490      Chart.DatasetController.extend = helpers.inherits;
4491  };
4492  },{}],24:[function(require,module,exports){
4493  "use strict";
4494  
4495  module.exports = function(Chart) {
4496  
4497    var helpers = Chart.helpers;
4498  
4499    Chart.elements = {};
4500  
4501    Chart.Element = function(configuration) {
4502      helpers.extend(this, configuration);
4503      this.initialize.apply(this, arguments);
4504    };
4505  
4506    helpers.extend(Chart.Element.prototype, {
4507  
4508      initialize: function() {
4509        this.hidden = false;
4510      },
4511  
4512      pivot: function() {
4513        var me = this;
4514        if (!me._view) {
4515          me._view = helpers.clone(me._model);
4516        }
4517        me._start = helpers.clone(me._view);
4518        return me;
4519      },
4520  
4521      transition: function(ease) {
4522        var me = this;
4523        
4524        if (!me._view) {
4525          me._view = helpers.clone(me._model);
4526        }
4527  
4528        // No animation -> No Transition

4529        if (ease === 1) {
4530          me._view = me._model;
4531          me._start = null;
4532          return me;
4533        }
4534  
4535        if (!me._start) {
4536          me.pivot();
4537        }
4538  
4539        helpers.each(me._model, function(value, key) {
4540  
4541          if (key[0] === '_') {
4542            // Only non-underscored properties

4543          }
4544  
4545          // Init if doesn't exist

4546          else if (!me._view.hasOwnProperty(key)) {
4547            if (typeof value === 'number' && !isNaN(me._view[key])) {
4548              me._view[key] = value * ease;
4549            } else {
4550              me._view[key] = value;
4551            }
4552          }
4553  
4554          // No unnecessary computations

4555          else if (value === me._view[key]) {
4556            // It's the same! Woohoo!

4557          }
4558  
4559          // Color transitions if possible

4560          else if (typeof value === 'string') {
4561            try {
4562              var color = helpers.color(me._model[key]).mix(helpers.color(me._start[key]), ease);
4563              me._view[key] = color.rgbString();
4564            } catch (err) {
4565              me._view[key] = value;
4566            }
4567          }
4568          // Number transitions

4569          else if (typeof value === 'number') {
4570            var startVal = me._start[key] !== undefined && isNaN(me._start[key]) === false ? me._start[key] : 0;
4571            me._view[key] = ((me._model[key] - startVal) * ease) + startVal;
4572          }
4573          // Everything else

4574          else {
4575            me._view[key] = value;
4576          }
4577        }, me);
4578  
4579        return me;
4580      },
4581  
4582      tooltipPosition: function() {
4583        return {
4584          x: this._model.x,
4585          y: this._model.y
4586        };
4587      },
4588  
4589      hasValue: function() {
4590        return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
4591      }
4592    });
4593  
4594    Chart.Element.extend = helpers.inherits;
4595  
4596  };
4597  
4598  },{}],25:[function(require,module,exports){
4599  /*global window: false */

4600  /*global document: false */

4601  "use strict";
4602  
4603  var color = require(3);
4604  
4605  module.exports = function(Chart) {
4606      //Global Chart helpers object for utility methods and classes

4607      var helpers = Chart.helpers = {};
4608  
4609      //-- Basic js utility methods

4610      helpers.each = function(loopable, callback, self, reverse) {
4611          // Check to see if null or undefined firstly.

4612          var i, len;
4613          if (helpers.isArray(loopable)) {
4614              len = loopable.length;
4615              if (reverse) {
4616                  for (i = len - 1; i >= 0; i--) {
4617                      callback.call(self, loopable[i], i);
4618                  }
4619              } else {
4620                  for (i = 0; i < len; i++) {
4621                      callback.call(self, loopable[i], i);
4622                  }
4623              }
4624          } else if (typeof loopable === 'object') {
4625              var keys = Object.keys(loopable);
4626              len = keys.length;
4627              for (i = 0; i < len; i++) {
4628                  callback.call(self, loopable[keys[i]], keys[i]);
4629              }
4630          }
4631      };
4632      helpers.clone = function(obj) {
4633          var objClone = {};
4634          helpers.each(obj, function(value, key) {
4635              if (helpers.isArray(value)) {
4636                  objClone[key] = value.slice(0);
4637              } else if (typeof value === 'object' && value !== null) {
4638                  objClone[key] = helpers.clone(value);
4639              } else {
4640                  objClone[key] = value;
4641              }
4642          });
4643          return objClone;
4644      };
4645      helpers.extend = function(base) {
4646          var setFn = function(value, key) { base[key] = value; };
4647          for (var i = 1, ilen = arguments.length; i < ilen; i++) {
4648              helpers.each(arguments[i], setFn);
4649          }
4650          return base;
4651      };
4652      // Need a special merge function to chart configs since they are now grouped

4653      helpers.configMerge = function(_base) {
4654          var base = helpers.clone(_base);
4655          helpers.each(Array.prototype.slice.call(arguments, 1), function(extension) {
4656              helpers.each(extension, function(value, key) {
4657                  if (key === 'scales') {
4658                      // Scale config merging is complex. Add out own function here for that

4659                      base[key] = helpers.scaleMerge(base.hasOwnProperty(key) ? base[key] : {}, value);
4660  
4661                  } else if (key === 'scale') {
4662                      // Used in polar area & radar charts since there is only one scale

4663                      base[key] = helpers.configMerge(base.hasOwnProperty(key) ? base[key] : {}, Chart.scaleService.getScaleDefaults(value.type), value);
4664                  } else if (base.hasOwnProperty(key) && helpers.isArray(base[key]) && helpers.isArray(value)) {
4665                      // In this case we have an array of objects replacing another array. Rather than doing a strict replace,

4666                      // merge. This allows easy scale option merging

4667                      var baseArray = base[key];
4668  
4669                      helpers.each(value, function(valueObj, index) {
4670  
4671                          if (index < baseArray.length) {
4672                              if (typeof baseArray[index] === 'object' && baseArray[index] !== null && typeof valueObj === 'object' && valueObj !== null) {
4673                                  // Two objects are coming together. Do a merge of them.

4674                                  baseArray[index] = helpers.configMerge(baseArray[index], valueObj);
4675                              } else {
4676                                  // Just overwrite in this case since there is nothing to merge

4677                                  baseArray[index] = valueObj;
4678                              }
4679                          } else {
4680                              baseArray.push(valueObj); // nothing to merge

4681                          }
4682                      });
4683  
4684                  } else if (base.hasOwnProperty(key) && typeof base[key] === "object" && base[key] !== null && typeof value === "object") {
4685                      // If we are overwriting an object with an object, do a merge of the properties.

4686                      base[key] = helpers.configMerge(base[key], value);
4687  
4688                  } else {
4689                      // can just overwrite the value in this case

4690                      base[key] = value;
4691                  }
4692              });
4693          });
4694  
4695          return base;
4696      };
4697      helpers.scaleMerge = function(_base, extension) {
4698          var base = helpers.clone(_base);
4699  
4700          helpers.each(extension, function(value, key) {
4701              if (key === 'xAxes' || key === 'yAxes') {
4702                  // These properties are arrays of items

4703                  if (base.hasOwnProperty(key)) {
4704                      helpers.each(value, function(valueObj, index) {
4705                          var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear');
4706                          var axisDefaults = Chart.scaleService.getScaleDefaults(axisType);
4707                          if (index >= base[key].length || !base[key][index].type) {
4708                              base[key].push(helpers.configMerge(axisDefaults, valueObj));
4709                          } else if (valueObj.type && valueObj.type !== base[key][index].type) {
4710                              // Type changed. Bring in the new defaults before we bring in valueObj so that valueObj can override the correct scale defaults

4711                              base[key][index] = helpers.configMerge(base[key][index], axisDefaults, valueObj);
4712                          } else {
4713                              // Type is the same

4714                              base[key][index] = helpers.configMerge(base[key][index], valueObj);
4715                          }
4716                      });
4717                  } else {
4718                      base[key] = [];
4719                      helpers.each(value, function(valueObj) {
4720                          var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear');
4721                          base[key].push(helpers.configMerge(Chart.scaleService.getScaleDefaults(axisType), valueObj));
4722                      });
4723                  }
4724              } else if (base.hasOwnProperty(key) && typeof base[key] === "object" && base[key] !== null && typeof value === "object") {
4725                  // If we are overwriting an object with an object, do a merge of the properties.

4726                  base[key] = helpers.configMerge(base[key], value);
4727  
4728              } else {
4729                  // can just overwrite the value in this case

4730                  base[key] = value;
4731              }
4732          });
4733  
4734          return base;
4735      };
4736      helpers.getValueAtIndexOrDefault = function(value, index, defaultValue) {
4737          if (value === undefined || value === null) {
4738              return defaultValue;
4739          }
4740  
4741          if (helpers.isArray(value)) {
4742              return index < value.length ? value[index] : defaultValue;
4743          }
4744  
4745          return value;
4746      };
4747      helpers.getValueOrDefault = function(value, defaultValue) {
4748          return value === undefined ? defaultValue : value;
4749      };
4750      helpers.indexOf = Array.prototype.indexOf?
4751          function(array, item) { return array.indexOf(item); } :
4752          function(array, item) {
4753              for (var i = 0, ilen = array.length; i < ilen; ++i) {
4754                  if (array[i] === item) {
4755                      return i;
4756                  }
4757              }
4758              return -1;
4759          };
4760      helpers.where = function(collection, filterCallback) {
4761          if (helpers.isArray(collection) && Array.prototype.filter) {
4762              return collection.filter(filterCallback);
4763          } else {
4764              var filtered = [];
4765  
4766              helpers.each(collection, function(item) {
4767                  if (filterCallback(item)) {
4768                      filtered.push(item);
4769                  }
4770              });
4771  
4772              return filtered;
4773          }
4774      };
4775      helpers.findIndex = Array.prototype.findIndex?
4776          function(array, callback, scope) { return array.findIndex(callback, scope); } :
4777          function(array, callback, scope) {
4778              scope = scope === undefined? array : scope;
4779              for (var i = 0, ilen = array.length; i < ilen; ++i) {
4780                  if (callback.call(scope, array[i], i, array)) {
4781                      return i;
4782                  }
4783              }
4784              return -1;
4785          };
4786      helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
4787          // Default to start of the array

4788          if (startIndex === undefined || startIndex === null) {
4789              startIndex = -1;
4790          }
4791          for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
4792              var currentItem = arrayToSearch[i];
4793              if (filterCallback(currentItem)) {
4794                  return currentItem;
4795              }
4796          }
4797      };
4798      helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
4799          // Default to end of the array

4800          if (startIndex === undefined || startIndex === null) {
4801              startIndex = arrayToSearch.length;
4802          }
4803          for (var i = startIndex - 1; i >= 0; i--) {
4804              var currentItem = arrayToSearch[i];
4805              if (filterCallback(currentItem)) {
4806                  return currentItem;
4807              }
4808          }
4809      };
4810      helpers.inherits = function(extensions) {
4811          //Basic javascript inheritance based on the model created in Backbone.js

4812          var parent = this;
4813          var ChartElement = (extensions && extensions.hasOwnProperty("constructor")) ? extensions.constructor : function() {
4814              return parent.apply(this, arguments);
4815          };
4816  
4817          var Surrogate = function() {
4818              this.constructor = ChartElement;
4819          };
4820          Surrogate.prototype = parent.prototype;
4821          ChartElement.prototype = new Surrogate();
4822  
4823          ChartElement.extend = helpers.inherits;
4824  
4825          if (extensions) {
4826              helpers.extend(ChartElement.prototype, extensions);
4827          }
4828  
4829          ChartElement.__super__ = parent.prototype;
4830  
4831          return ChartElement;
4832      };
4833      helpers.noop = function() {};
4834      helpers.uid = (function() {
4835          var id = 0;
4836          return function() {
4837              return id++;
4838          };
4839      })();
4840      //-- Math methods

4841      helpers.isNumber = function(n) {
4842          return !isNaN(parseFloat(n)) && isFinite(n);
4843      };
4844      helpers.almostEquals = function(x, y, epsilon) {
4845          return Math.abs(x - y) < epsilon;
4846      };
4847      helpers.max = function(array) {
4848          return array.reduce(function(max, value) {
4849              if (!isNaN(value)) {
4850                  return Math.max(max, value);
4851              } else {
4852                  return max;
4853              }
4854          }, Number.NEGATIVE_INFINITY);
4855      };
4856      helpers.min = function(array) {
4857          return array.reduce(function(min, value) {
4858              if (!isNaN(value)) {
4859                  return Math.min(min, value);
4860              } else {
4861                  return min;
4862              }
4863          }, Number.POSITIVE_INFINITY);
4864      };
4865      helpers.sign = Math.sign?
4866          function(x) { return Math.sign(x); } :
4867          function(x) {
4868              x = +x; // convert to a number

4869              if (x === 0 || isNaN(x)) {
4870                  return x;
4871              }
4872              return x > 0 ? 1 : -1;
4873          };
4874      helpers.log10 = Math.log10?
4875          function(x) { return Math.log10(x); } :
4876          function(x) {
4877              return Math.log(x) / Math.LN10;
4878          };
4879      helpers.toRadians = function(degrees) {
4880          return degrees * (Math.PI / 180);
4881      };
4882      helpers.toDegrees = function(radians) {
4883          return radians * (180 / Math.PI);
4884      };
4885      // Gets the angle from vertical upright to the point about a centre.

4886      helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
4887          var distanceFromXCenter = anglePoint.x - centrePoint.x,
4888              distanceFromYCenter = anglePoint.y - centrePoint.y,
4889              radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
4890  
4891          var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
4892  
4893          if (angle < (-0.5 * Math.PI)) {
4894              angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]

4895          }
4896  
4897          return {
4898              angle: angle,
4899              distance: radialDistanceFromCenter
4900          };
4901      };
4902      helpers.aliasPixel = function(pixelWidth) {
4903          return (pixelWidth % 2 === 0) ? 0 : 0.5;
4904      };
4905      helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
4906          //Props to Rob Spencer at scaled innovation for his post on splining between points

4907          //http://scaledinnovation.com/analytics/splines/aboutSplines.html

4908  
4909          // This function must also respect "skipped" points

4910  
4911          var previous = firstPoint.skip ? middlePoint : firstPoint,
4912              current = middlePoint,
4913              next = afterPoint.skip ? middlePoint : afterPoint;
4914  
4915          var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
4916          var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
4917  
4918          var s01 = d01 / (d01 + d12);
4919          var s12 = d12 / (d01 + d12);
4920  
4921          // If all points are the same, s01 & s02 will be inf

4922          s01 = isNaN(s01) ? 0 : s01;
4923          s12 = isNaN(s12) ? 0 : s12;
4924  
4925          var fa = t * s01; // scaling factor for triangle Ta

4926          var fb = t * s12;
4927  
4928          return {
4929              previous: {
4930                  x: current.x - fa * (next.x - previous.x),
4931                  y: current.y - fa * (next.y - previous.y)
4932              },
4933              next: {
4934                  x: current.x + fb * (next.x - previous.x),
4935                  y: current.y + fb * (next.y - previous.y)
4936              }
4937          };
4938      };
4939      helpers.nextItem = function(collection, index, loop) {
4940          if (loop) {
4941              return index >= collection.length - 1 ? collection[0] : collection[index + 1];
4942          }
4943  
4944          return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
4945      };
4946      helpers.previousItem = function(collection, index, loop) {
4947          if (loop) {
4948              return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
4949          }
4950          return index <= 0 ? collection[0] : collection[index - 1];
4951      };
4952      // Implementation of the nice number algorithm used in determining where axis labels will go

4953      helpers.niceNum = function(range, round) {
4954          var exponent = Math.floor(helpers.log10(range));
4955          var fraction = range / Math.pow(10, exponent);
4956          var niceFraction;
4957  
4958          if (round) {
4959              if (fraction < 1.5) {
4960                  niceFraction = 1;
4961              } else if (fraction < 3) {
4962                  niceFraction = 2;
4963              } else if (fraction < 7) {
4964                  niceFraction = 5;
4965              } else {
4966                  niceFraction = 10;
4967              }
4968          } else {
4969              if (fraction <= 1.0) {
4970                  niceFraction = 1;
4971              } else if (fraction <= 2) {
4972                  niceFraction = 2;
4973              } else if (fraction <= 5) {
4974                  niceFraction = 5;
4975              } else {
4976                  niceFraction = 10;
4977              }
4978          }
4979  
4980          return niceFraction * Math.pow(10, exponent);
4981      };
4982      //Easing functions adapted from Robert Penner's easing equations

4983      //http://www.robertpenner.com/easing/

4984      var easingEffects = helpers.easingEffects = {
4985          linear: function(t) {
4986              return t;
4987          },
4988          easeInQuad: function(t) {
4989              return t * t;
4990          },
4991          easeOutQuad: function(t) {
4992              return -1 * t * (t - 2);
4993          },
4994          easeInOutQuad: function(t) {
4995              if ((t /= 1 / 2) < 1) {
4996                  return 1 / 2 * t * t;
4997              }
4998              return -1 / 2 * ((--t) * (t - 2) - 1);
4999          },
5000          easeInCubic: function(t) {
5001              return t * t * t;
5002          },
5003          easeOutCubic: function(t) {
5004              return 1 * ((t = t / 1 - 1) * t * t + 1);
5005          },
5006          easeInOutCubic: function(t) {
5007              if ((t /= 1 / 2) < 1) {
5008                  return 1 / 2 * t * t * t;
5009              }
5010              return 1 / 2 * ((t -= 2) * t * t + 2);
5011          },
5012          easeInQuart: function(t) {
5013              return t * t * t * t;
5014          },
5015          easeOutQuart: function(t) {
5016              return -1 * ((t = t / 1 - 1) * t * t * t - 1);
5017          },
5018          easeInOutQuart: function(t) {
5019              if ((t /= 1 / 2) < 1) {
5020                  return 1 / 2 * t * t * t * t;
5021              }
5022              return -1 / 2 * ((t -= 2) * t * t * t - 2);
5023          },
5024          easeInQuint: function(t) {
5025              return 1 * (t /= 1) * t * t * t * t;
5026          },
5027          easeOutQuint: function(t) {
5028              return 1 * ((t = t / 1 - 1) * t * t * t * t + 1);
5029          },
5030          easeInOutQuint: function(t) {
5031              if ((t /= 1 / 2) < 1) {
5032                  return 1 / 2 * t * t * t * t * t;
5033              }
5034              return 1 / 2 * ((t -= 2) * t * t * t * t + 2);
5035          },
5036          easeInSine: function(t) {
5037              return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1;
5038          },
5039          easeOutSine: function(t) {
5040              return 1 * Math.sin(t / 1 * (Math.PI / 2));
5041          },
5042          easeInOutSine: function(t) {
5043              return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1);
5044          },
5045          easeInExpo: function(t) {
5046              return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1));
5047          },
5048          easeOutExpo: function(t) {
5049              return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1);
5050          },
5051          easeInOutExpo: function(t) {
5052              if (t === 0) {
5053                  return 0;
5054              }
5055              if (t === 1) {
5056                  return 1;
5057              }
5058              if ((t /= 1 / 2) < 1) {
5059                  return 1 / 2 * Math.pow(2, 10 * (t - 1));
5060              }
5061              return 1 / 2 * (-Math.pow(2, -10 * --t) + 2);
5062          },
5063          easeInCirc: function(t) {
5064              if (t >= 1) {
5065                  return t;
5066              }
5067              return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1);
5068          },
5069          easeOutCirc: function(t) {
5070              return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t);
5071          },
5072          easeInOutCirc: function(t) {
5073              if ((t /= 1 / 2) < 1) {
5074                  return -1 / 2 * (Math.sqrt(1 - t * t) - 1);
5075              }
5076              return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1);
5077          },
5078          easeInElastic: function(t) {
5079              var s = 1.70158;
5080              var p = 0;
5081              var a = 1;
5082              if (t === 0) {
5083                  return 0;
5084              }
5085              if ((t /= 1) === 1) {
5086                  return 1;
5087              }
5088              if (!p) {
5089                  p = 1 * 0.3;
5090              }
5091              if (a < Math.abs(1)) {
5092                  a = 1;
5093                  s = p / 4;
5094              } else {
5095                  s = p / (2 * Math.PI) * Math.asin(1 / a);
5096              }
5097              return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
5098          },
5099          easeOutElastic: function(t) {
5100              var s = 1.70158;
5101              var p = 0;
5102              var a = 1;
5103              if (t === 0) {
5104                  return 0;
5105              }
5106              if ((t /= 1) === 1) {
5107                  return 1;
5108              }
5109              if (!p) {
5110                  p = 1 * 0.3;
5111              }
5112              if (a < Math.abs(1)) {
5113                  a = 1;
5114                  s = p / 4;
5115              } else {
5116                  s = p / (2 * Math.PI) * Math.asin(1 / a);
5117              }
5118              return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
5119          },
5120          easeInOutElastic: function(t) {
5121              var s = 1.70158;
5122              var p = 0;
5123              var a = 1;
5124              if (t === 0) {
5125                  return 0;
5126              }
5127              if ((t /= 1 / 2) === 2) {
5128                  return 1;
5129              }
5130              if (!p) {
5131                  p = 1 * (0.3 * 1.5);
5132              }
5133              if (a < Math.abs(1)) {
5134                  a = 1;
5135                  s = p / 4;
5136              } else {
5137                  s = p / (2 * Math.PI) * Math.asin(1 / a);
5138              }
5139              if (t < 1) {
5140                  return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
5141              }
5142              return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1;
5143          },
5144          easeInBack: function(t) {
5145              var s = 1.70158;
5146              return 1 * (t /= 1) * t * ((s + 1) * t - s);
5147          },
5148          easeOutBack: function(t) {
5149              var s = 1.70158;
5150              return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1);
5151          },
5152          easeInOutBack: function(t) {
5153              var s = 1.70158;
5154              if ((t /= 1 / 2) < 1) {
5155                  return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s));
5156              }
5157              return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
5158          },
5159          easeInBounce: function(t) {
5160              return 1 - easingEffects.easeOutBounce(1 - t);
5161          },
5162          easeOutBounce: function(t) {
5163              if ((t /= 1) < (1 / 2.75)) {
5164                  return 1 * (7.5625 * t * t);
5165              } else if (t < (2 / 2.75)) {
5166                  return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
5167              } else if (t < (2.5 / 2.75)) {
5168                  return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
5169              } else {
5170                  return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
5171              }
5172          },
5173          easeInOutBounce: function(t) {
5174              if (t < 1 / 2) {
5175                  return easingEffects.easeInBounce(t * 2) * 0.5;
5176              }
5177              return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
5178          }
5179      };
5180      //Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

5181      helpers.requestAnimFrame = (function() {
5182          return window.requestAnimationFrame ||
5183              window.webkitRequestAnimationFrame ||
5184              window.mozRequestAnimationFrame ||
5185              window.oRequestAnimationFrame ||
5186              window.msRequestAnimationFrame ||
5187              function(callback) {
5188                  return window.setTimeout(callback, 1000 / 60);
5189              };
5190      })();
5191      helpers.cancelAnimFrame = (function() {
5192          return window.cancelAnimationFrame ||
5193              window.webkitCancelAnimationFrame ||
5194              window.mozCancelAnimationFrame ||
5195              window.oCancelAnimationFrame ||
5196              window.msCancelAnimationFrame ||
5197              function(callback) {
5198                  return window.clearTimeout(callback, 1000 / 60);
5199              };
5200      })();
5201      //-- DOM methods

5202      helpers.getRelativePosition = function(evt, chart) {
5203          var mouseX, mouseY;
5204          var e = evt.originalEvent || evt,
5205              canvas = evt.currentTarget || evt.srcElement,
5206              boundingRect = canvas.getBoundingClientRect();
5207  
5208          var touches = e.touches;
5209          if (touches && touches.length > 0) {
5210              mouseX = touches[0].clientX;
5211              mouseY = touches[0].clientY;
5212  
5213          } else {
5214              mouseX = e.clientX;
5215              mouseY = e.clientY;
5216          }
5217  
5218          // Scale mouse coordinates into canvas coordinates

5219          // by following the pattern laid out by 'jerryj' in the comments of

5220          // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

5221          var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
5222          var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
5223          var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
5224          var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
5225          var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
5226          var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
5227  
5228          // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However

5229          // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here

5230          mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
5231          mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
5232  
5233          return {
5234              x: mouseX,
5235              y: mouseY
5236          };
5237  
5238      };
5239      helpers.addEvent = function(node, eventType, method) {
5240          if (node.addEventListener) {
5241              node.addEventListener(eventType, method);
5242          } else if (node.attachEvent) {
5243              node.attachEvent("on" + eventType, method);
5244          } else {
5245              node["on" + eventType] = method;
5246          }
5247      };
5248      helpers.removeEvent = function(node, eventType, handler) {
5249          if (node.removeEventListener) {
5250              node.removeEventListener(eventType, handler, false);
5251          } else if (node.detachEvent) {
5252              node.detachEvent("on" + eventType, handler);
5253          } else {
5254              node["on" + eventType] = helpers.noop;
5255          }
5256      };
5257      helpers.bindEvents = function(chartInstance, arrayOfEvents, handler) {
5258          // Create the events object if it's not already present

5259          var events = chartInstance.events = chartInstance.events || {};
5260  
5261          helpers.each(arrayOfEvents, function(eventName) {
5262              events[eventName] = function() {
5263                  handler.apply(chartInstance, arguments);
5264              };
5265              helpers.addEvent(chartInstance.chart.canvas, eventName, events[eventName]);
5266          });
5267      };
5268      helpers.unbindEvents = function(chartInstance, arrayOfEvents) {
5269          var canvas = chartInstance.chart.canvas;
5270          helpers.each(arrayOfEvents, function(handler, eventName) {
5271              helpers.removeEvent(canvas, eventName, handler);
5272          });
5273      };
5274  
5275      // Private helper function to convert max-width/max-height values that may be percentages into a number

5276  	function parseMaxStyle(styleValue, node, parentProperty) {
5277          var valueInPixels;
5278          if (typeof(styleValue) === 'string') {
5279              valueInPixels = parseInt(styleValue, 10);
5280  
5281              if (styleValue.indexOf('%') != -1) {
5282                  // percentage * size in dimension

5283                  valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
5284              }
5285          } else {
5286              valueInPixels = styleValue;
5287          }
5288  
5289          return valueInPixels;
5290      }
5291  
5292      /**

5293       * Returns if the given value contains an effective constraint.

5294       * @private

5295       */
5296  	function isConstrainedValue(value) {
5297          return value !== undefined &&  value !== null && value !== 'none';
5298      }
5299  
5300      // Private helper to get a constraint dimension

5301      // @param domNode : the node to check the constraint on

5302      // @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)

5303      // @param percentageProperty : property of parent to use when calculating width as a percentage

5304      // @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser

5305  	function getConstraintDimension(domNode, maxStyle, percentageProperty) {
5306          var view = document.defaultView;
5307          var parentNode = domNode.parentNode;
5308          var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
5309          var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
5310          var hasCNode = isConstrainedValue(constrainedNode);
5311          var hasCContainer = isConstrainedValue(constrainedContainer);
5312          var infinity = Number.POSITIVE_INFINITY;
5313  
5314          if (hasCNode || hasCContainer) {
5315              return Math.min(
5316                  hasCNode? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
5317                  hasCContainer? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
5318          }
5319  
5320          return 'none';
5321      }
5322      // returns Number or undefined if no constraint

5323      helpers.getConstraintWidth = function(domNode) {
5324          return getConstraintDimension(domNode, 'max-width', 'clientWidth');
5325      };
5326      // returns Number or undefined if no constraint

5327      helpers.getConstraintHeight = function(domNode) {
5328          return getConstraintDimension(domNode, 'max-height', 'clientHeight');
5329      };
5330      helpers.getMaximumWidth = function(domNode) {
5331          var container = domNode.parentNode;
5332          var padding = parseInt(helpers.getStyle(container, 'padding-left')) + parseInt(helpers.getStyle(container, 'padding-right'));
5333          var w = container.clientWidth - padding;
5334          var cw = helpers.getConstraintWidth(domNode);
5335          return isNaN(cw)? w : Math.min(w, cw);
5336      };
5337      helpers.getMaximumHeight = function(domNode) {
5338          var container = domNode.parentNode;
5339          var padding = parseInt(helpers.getStyle(container, 'padding-top')) + parseInt(helpers.getStyle(container, 'padding-bottom'));
5340          var h = container.clientHeight - padding;
5341          var ch = helpers.getConstraintHeight(domNode);
5342          return isNaN(ch)? h : Math.min(h, ch);
5343      };
5344      helpers.getStyle = function(el, property) {
5345          return el.currentStyle ?
5346              el.currentStyle[property] :
5347              document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
5348      };
5349      helpers.retinaScale = function(chart) {
5350          var ctx = chart.ctx;
5351          var canvas = chart.canvas;
5352          var width = canvas.width;
5353          var height = canvas.height;
5354          var pixelRatio = chart.currentDevicePixelRatio = window.devicePixelRatio || 1;
5355  
5356          if (pixelRatio !== 1) {
5357              canvas.height = height * pixelRatio;
5358              canvas.width = width * pixelRatio;
5359              ctx.scale(pixelRatio, pixelRatio);
5360  
5361              // Store the device pixel ratio so that we can go backwards in `destroy`.

5362              // The devicePixelRatio changes with zoom, so there are no guarantees that it is the same

5363              // when destroy is called

5364              chart.originalDevicePixelRatio = chart.originalDevicePixelRatio || pixelRatio;
5365          }
5366  
5367          canvas.style.width = width + 'px';
5368          canvas.style.height = height + 'px';
5369      };
5370      //-- Canvas methods

5371      helpers.clear = function(chart) {
5372          chart.ctx.clearRect(0, 0, chart.width, chart.height);
5373      };
5374      helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
5375          return fontStyle + " " + pixelSize + "px " + fontFamily;
5376      };
5377      helpers.longestText = function(ctx, font, arrayOfThings, cache) {
5378          cache = cache || {};
5379          var data = cache.data = cache.data || {};
5380          var gc = cache.garbageCollect = cache.garbageCollect || [];
5381  
5382          if (cache.font !== font) {
5383              data = cache.data = {};
5384              gc = cache.garbageCollect = [];
5385              cache.font = font;
5386          }
5387  
5388          ctx.font = font;
5389          var longest = 0;
5390          helpers.each(arrayOfThings, function(thing) {
5391              // Undefined strings and arrays should not be measured

5392              if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
5393                  longest = helpers.measureText(ctx, data, gc, longest, thing);
5394              } else if (helpers.isArray(thing)) {
5395                  // if it is an array lets measure each element

5396                  // to do maybe simplify this function a bit so we can do this more recursively?

5397                  helpers.each(thing, function(nestedThing) {
5398                      // Undefined strings and arrays should not be measured

5399                      if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
5400                          longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
5401                      }
5402                  });
5403              }
5404          });
5405  
5406          var gcLen = gc.length / 2;
5407          if (gcLen > arrayOfThings.length) {
5408              for (var i = 0; i < gcLen; i++) {
5409                  delete data[gc[i]];
5410              }
5411              gc.splice(0, gcLen);
5412          }
5413          return longest;
5414      };
5415      helpers.measureText = function (ctx, data, gc, longest, string) {
5416          var textWidth = data[string];
5417          if (!textWidth) {
5418              textWidth = data[string] = ctx.measureText(string).width;
5419              gc.push(string);
5420          }
5421          if (textWidth > longest) {
5422              longest = textWidth;
5423          }
5424          return longest;
5425      };
5426      helpers.numberOfLabelLines = function(arrayOfThings) {
5427          var numberOfLines = 1;
5428          helpers.each(arrayOfThings, function(thing) {
5429              if (helpers.isArray(thing)) {
5430                  if (thing.length > numberOfLines) {
5431                      numberOfLines = thing.length;
5432                  }
5433              }
5434          });
5435          return numberOfLines;
5436      };
5437      helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) {
5438          ctx.beginPath();
5439          ctx.moveTo(x + radius, y);
5440          ctx.lineTo(x + width - radius, y);
5441          ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
5442          ctx.lineTo(x + width, y + height - radius);
5443          ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
5444          ctx.lineTo(x + radius, y + height);
5445          ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
5446          ctx.lineTo(x, y + radius);
5447          ctx.quadraticCurveTo(x, y, x + radius, y);
5448          ctx.closePath();
5449      };
5450      helpers.color = function(c) {
5451          if (!color) {
5452              console.log('Color.js not found!');
5453              return c;
5454          }
5455  
5456          /* global CanvasGradient */

5457          if (c instanceof CanvasGradient) {
5458              return color(Chart.defaults.global.defaultColor);
5459          }
5460  
5461          return color(c);
5462      };
5463      helpers.addResizeListener = function(node, callback) {
5464          // Hide an iframe before the node

5465          var hiddenIframe = document.createElement('iframe');
5466          var hiddenIframeClass = 'chartjs-hidden-iframe';
5467  
5468          if (hiddenIframe.classlist) {
5469              // can use classlist

5470              hiddenIframe.classlist.add(hiddenIframeClass);
5471          } else {
5472              hiddenIframe.setAttribute('class', hiddenIframeClass);
5473          }
5474  
5475          // Set the style

5476          var style = hiddenIframe.style;
5477          style.width = '100%';
5478          style.display = 'block';
5479          style.border = 0;
5480          style.height = 0;
5481          style.margin = 0;
5482          style.position = 'absolute';
5483          style.left = 0;
5484          style.right = 0;
5485          style.top = 0;
5486          style.bottom = 0;
5487  
5488          // Insert the iframe so that contentWindow is available

5489          node.insertBefore(hiddenIframe, node.firstChild);
5490  
5491          (hiddenIframe.contentWindow || hiddenIframe).onresize = function() {
5492              if (callback) {
5493                  callback();
5494              }
5495          };
5496      };
5497      helpers.removeResizeListener = function(node) {
5498          var hiddenIframe = node.querySelector('.chartjs-hidden-iframe');
5499  
5500          // Remove the resize detect iframe

5501          if (hiddenIframe) {
5502              hiddenIframe.parentNode.removeChild(hiddenIframe);
5503          }
5504      };
5505      helpers.isArray = Array.isArray?
5506          function(obj) { return Array.isArray(obj); } :
5507          function(obj) {
5508              return Object.prototype.toString.call(obj) === '[object Array]';
5509          };
5510      //! @see http://stackoverflow.com/a/14853974

5511      helpers.arrayEquals = function(a0, a1) {
5512          var i, ilen, v0, v1;
5513  
5514          if (!a0 || !a1 || a0.length != a1.length) {
5515              return false;
5516          }
5517  
5518          for (i = 0, ilen=a0.length; i < ilen; ++i) {
5519              v0 = a0[i];
5520              v1 = a1[i];
5521  
5522              if (v0 instanceof Array && v1 instanceof Array) {
5523                  if (!helpers.arrayEquals(v0, v1)) {
5524                      return false;
5525                  }
5526              } else if (v0 != v1) {
5527                  // NOTE: two different object instances will never be equal: {x:20} != {x:20}

5528                  return false;
5529              }
5530          }
5531  
5532          return true;
5533      };
5534      helpers.callCallback = function(fn, args, _tArg) {
5535          if (fn && typeof fn.call === 'function') {
5536              fn.apply(_tArg, args);
5537          }
5538      };
5539      helpers.getHoverColor = function(color) {
5540          /* global CanvasPattern */

5541          return (color instanceof CanvasPattern) ?
5542              color :
5543              helpers.color(color).saturate(0.5).darken(0.1).rgbString();
5544      };
5545  };
5546  
5547  },{"3":3}],26:[function(require,module,exports){
5548  "use strict";
5549  
5550  module.exports = function() {
5551  
5552      //Occupy the global variable of Chart, and create a simple base class

5553      var Chart = function(context, config) {
5554          var me = this;
5555          var helpers = Chart.helpers;
5556          me.config = config;
5557  
5558          // Support a jQuery'd canvas element

5559          if (context.length && context[0].getContext) {
5560              context = context[0];
5561          }
5562  
5563          // Support a canvas domnode

5564          if (context.getContext) {
5565              context = context.getContext("2d");
5566          }
5567  
5568          me.ctx = context;
5569          me.canvas = context.canvas;
5570  
5571          context.canvas.style.display = context.canvas.style.display || 'block';
5572  
5573          // Figure out what the size of the chart will be.

5574          // If the canvas has a specified width and height, we use those else

5575          // we look to see if the canvas node has a CSS width and height.

5576          // If there is still no height, fill the parent container

5577          me.width = context.canvas.width || parseInt(helpers.getStyle(context.canvas, 'width'), 10) || helpers.getMaximumWidth(context.canvas);
5578          me.height = context.canvas.height || parseInt(helpers.getStyle(context.canvas, 'height'), 10) || helpers.getMaximumHeight(context.canvas);
5579  
5580          me.aspectRatio = me.width / me.height;
5581  
5582          if (isNaN(me.aspectRatio) || isFinite(me.aspectRatio) === false) {
5583              // If the canvas has no size, try and figure out what the aspect ratio will be.

5584              // Some charts prefer square canvases (pie, radar, etc). If that is specified, use that

5585              // else use the canvas default ratio of 2

5586              me.aspectRatio = config.aspectRatio !== undefined ? config.aspectRatio : 2;
5587          }
5588  
5589          // Store the original style of the element so we can set it back

5590          me.originalCanvasStyleWidth = context.canvas.style.width;
5591          me.originalCanvasStyleHeight = context.canvas.style.height;
5592  
5593          // High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.

5594          helpers.retinaScale(me);
5595  
5596          if (config) {
5597              me.controller = new Chart.Controller(me);
5598          }
5599  
5600          // Always bind this so that if the responsive state changes we still work

5601          helpers.addResizeListener(context.canvas.parentNode, function() {
5602              if (me.controller && me.controller.config.options.responsive) {
5603                  me.controller.resize();
5604              }
5605          });
5606  
5607          return me.controller ? me.controller : me;
5608  
5609      };
5610  
5611      //Globally expose the defaults to allow for user updating/changing

5612      Chart.defaults = {
5613          global: {
5614              responsive: true,
5615              responsiveAnimationDuration: 0,
5616              maintainAspectRatio: true,
5617              events: ["mousemove", "mouseout", "click", "touchstart", "touchmove"],
5618              hover: {
5619                  onHover: null,
5620                  mode: 'single',
5621                  animationDuration: 400
5622              },
5623              onClick: null,
5624              defaultColor: 'rgba(0,0,0,0.1)',
5625              defaultFontColor: '#666',
5626              defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
5627              defaultFontSize: 12,
5628              defaultFontStyle: 'normal',
5629              showLines: true,
5630  
5631              // Element defaults defined in element extensions

5632              elements: {},
5633  
5634              // Legend callback string

5635              legendCallback: function(chart) {
5636                  var text = [];
5637                  text.push('<ul class="' + chart.id + '-legend">');
5638                  for (var i = 0; i < chart.data.datasets.length; i++) {
5639                      text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
5640                      if (chart.data.datasets[i].label) {
5641                          text.push(chart.data.datasets[i].label);
5642                      }
5643                      text.push('</li>');
5644                  }
5645                  text.push('</ul>');
5646  
5647                  return text.join("");
5648              }
5649          }
5650      };
5651  
5652      Chart.Chart = Chart;
5653  
5654      return Chart;
5655  
5656  };
5657  
5658  },{}],27:[function(require,module,exports){
5659  "use strict";
5660  
5661  module.exports = function(Chart) {
5662  
5663      var helpers = Chart.helpers;
5664  
5665      // The layout service is very self explanatory.  It's responsible for the layout within a chart.

5666      // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need

5667      // It is this service's responsibility of carrying out that layout.

5668      Chart.layoutService = {
5669          defaults: {},
5670  
5671          // Register a box to a chartInstance. A box is simply a reference to an object that requires layout. eg. Scales, Legend, Plugins.

5672          addBox: function(chartInstance, box) {
5673              if (!chartInstance.boxes) {
5674                  chartInstance.boxes = [];
5675              }
5676              chartInstance.boxes.push(box);
5677          },
5678  
5679          removeBox: function(chartInstance, box) {
5680              if (!chartInstance.boxes) {
5681                  return;
5682              }
5683              chartInstance.boxes.splice(chartInstance.boxes.indexOf(box), 1);
5684          },
5685  
5686          // The most important function

5687          update: function(chartInstance, width, height) {
5688  
5689              if (!chartInstance) {
5690                  return;
5691              }
5692  
5693              var xPadding = 0;
5694              var yPadding = 0;
5695  
5696              var leftBoxes = helpers.where(chartInstance.boxes, function(box) {
5697                  return box.options.position === "left";
5698              });
5699              var rightBoxes = helpers.where(chartInstance.boxes, function(box) {
5700                  return box.options.position === "right";
5701              });
5702              var topBoxes = helpers.where(chartInstance.boxes, function(box) {
5703                  return box.options.position === "top";
5704              });
5705              var bottomBoxes = helpers.where(chartInstance.boxes, function(box) {
5706                  return box.options.position === "bottom";
5707              });
5708  
5709              // Boxes that overlay the chartarea such as the radialLinear scale

5710              var chartAreaBoxes = helpers.where(chartInstance.boxes, function(box) {
5711                  return box.options.position === "chartArea";
5712              });
5713  
5714              // Ensure that full width boxes are at the very top / bottom

5715              topBoxes.sort(function(a, b) {
5716                  return (b.options.fullWidth ? 1 : 0) - (a.options.fullWidth ? 1 : 0);
5717              });
5718              bottomBoxes.sort(function(a, b) {
5719                  return (a.options.fullWidth ? 1 : 0) - (b.options.fullWidth ? 1 : 0);
5720              });
5721  
5722              // Essentially we now have any number of boxes on each of the 4 sides.

5723              // Our canvas looks like the following.

5724              // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and

5725              // B1 is the bottom axis

5726              // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays

5727              // These locations are single-box locations only, when trying to register a chartArea location that is already taken,

5728              // an error will be thrown.

5729              //

5730              // |----------------------------------------------------|

5731              // |                  T1 (Full Width)                   |

5732              // |----------------------------------------------------|

5733              // |    |    |                 T2                  |    |

5734              // |    |----|-------------------------------------|----|

5735              // |    |    | C1 |                           | C2 |    |

5736              // |    |    |----|                           |----|    |

5737              // |    |    |                                     |    |

5738              // | L1 | L2 |           ChartArea (C0)            | R1 |

5739              // |    |    |                                     |    |

5740              // |    |    |----|                           |----|    |

5741              // |    |    | C3 |                           | C4 |    |

5742              // |    |----|-------------------------------------|----|

5743              // |    |    |                 B1                  |    |

5744              // |----------------------------------------------------|

5745              // |                  B2 (Full Width)                   |

5746              // |----------------------------------------------------|

5747              //

5748              // What we do to find the best sizing, we do the following

5749              // 1. Determine the minimum size of the chart area.

5750              // 2. Split the remaining width equally between each vertical axis

5751              // 3. Split the remaining height equally between each horizontal axis

5752              // 4. Give each layout the maximum size it can be. The layout will return it's minimum size

5753              // 5. Adjust the sizes of each axis based on it's minimum reported size.

5754              // 6. Refit each axis

5755              // 7. Position each axis in the final location

5756              // 8. Tell the chart the final location of the chart area

5757              // 9. Tell any axes that overlay the chart area the positions of the chart area

5758  
5759              // Step 1

5760              var chartWidth = width - (2 * xPadding);
5761              var chartHeight = height - (2 * yPadding);
5762              var chartAreaWidth = chartWidth / 2; // min 50%

5763              var chartAreaHeight = chartHeight / 2; // min 50%

5764  
5765              // Step 2

5766              var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
5767  
5768              // Step 3

5769              var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
5770  
5771              // Step 4

5772              var maxChartAreaWidth = chartWidth;
5773              var maxChartAreaHeight = chartHeight;
5774              var minBoxSizes = [];
5775  
5776              helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
5777  
5778  			function getMinimumBoxSize(box) {
5779                  var minSize;
5780                  var isHorizontal = box.isHorizontal();
5781  
5782                  if (isHorizontal) {
5783                      minSize = box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
5784                      maxChartAreaHeight -= minSize.height;
5785                  } else {
5786                      minSize = box.update(verticalBoxWidth, chartAreaHeight);
5787                      maxChartAreaWidth -= minSize.width;
5788                  }
5789  
5790                  minBoxSizes.push({
5791                      horizontal: isHorizontal,
5792                      minSize: minSize,
5793                      box: box
5794                  });
5795              }
5796  
5797              // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could

5798              // be if the axes are drawn at their minimum sizes.

5799  
5800              // Steps 5 & 6

5801              var totalLeftBoxesWidth = xPadding;
5802              var totalRightBoxesWidth = xPadding;
5803              var totalTopBoxesHeight = yPadding;
5804              var totalBottomBoxesHeight = yPadding;
5805  
5806              // Update, and calculate the left and right margins for the horizontal boxes

5807              helpers.each(leftBoxes.concat(rightBoxes), fitBox);
5808  
5809              helpers.each(leftBoxes, function(box) {
5810                  totalLeftBoxesWidth += box.width;
5811              });
5812  
5813              helpers.each(rightBoxes, function(box) {
5814                  totalRightBoxesWidth += box.width;
5815              });
5816  
5817              // Set the Left and Right margins for the horizontal boxes

5818              helpers.each(topBoxes.concat(bottomBoxes), fitBox);
5819  
5820              // Function to fit a box

5821  			function fitBox(box) {
5822                  var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
5823                      return minBoxSize.box === box;
5824                  });
5825  
5826                  if (minBoxSize) {
5827                      if (box.isHorizontal()) {
5828                          var scaleMargin = {
5829                              left: totalLeftBoxesWidth,
5830                              right: totalRightBoxesWidth,
5831                              top: 0,
5832                              bottom: 0
5833                          };
5834  
5835                          // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends

5836                          // on the margin. Sometimes they need to increase in size slightly

5837                          box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
5838                      } else {
5839                          box.update(minBoxSize.minSize.width, maxChartAreaHeight);
5840                      }
5841                  }
5842              }
5843  
5844              // Figure out how much margin is on the top and bottom of the vertical boxes

5845              helpers.each(topBoxes, function(box) {
5846                  totalTopBoxesHeight += box.height;
5847              });
5848  
5849              helpers.each(bottomBoxes, function(box) {
5850                  totalBottomBoxesHeight += box.height;
5851              });
5852  
5853              // Let the left layout know the final margin

5854              helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
5855  
5856  			function finalFitVerticalBox(box) {
5857                  var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
5858                      return minBoxSize.box === box;
5859                  });
5860  
5861                  var scaleMargin = {
5862                      left: 0,
5863                      right: 0,
5864                      top: totalTopBoxesHeight,
5865                      bottom: totalBottomBoxesHeight
5866                  };
5867  
5868                  if (minBoxSize) {
5869                      box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
5870                  }
5871              }
5872  
5873              // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)

5874              totalLeftBoxesWidth = xPadding;
5875              totalRightBoxesWidth = xPadding;
5876              totalTopBoxesHeight = yPadding;
5877              totalBottomBoxesHeight = yPadding;
5878  
5879              helpers.each(leftBoxes, function(box) {
5880                  totalLeftBoxesWidth += box.width;
5881              });
5882  
5883              helpers.each(rightBoxes, function(box) {
5884                  totalRightBoxesWidth += box.width;
5885              });
5886  
5887              helpers.each(topBoxes, function(box) {
5888                  totalTopBoxesHeight += box.height;
5889              });
5890              helpers.each(bottomBoxes, function(box) {
5891                  totalBottomBoxesHeight += box.height;
5892              });
5893  
5894              // Figure out if our chart area changed. This would occur if the dataset layout label rotation

5895              // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do

5896              // without calling `fit` again

5897              var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
5898              var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
5899  
5900              if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
5901                  helpers.each(leftBoxes, function(box) {
5902                      box.height = newMaxChartAreaHeight;
5903                  });
5904  
5905                  helpers.each(rightBoxes, function(box) {
5906                      box.height = newMaxChartAreaHeight;
5907                  });
5908  
5909                  helpers.each(topBoxes, function(box) {
5910                      if (!box.options.fullWidth) {
5911                          box.width = newMaxChartAreaWidth;
5912                      }
5913                  });
5914  
5915                  helpers.each(bottomBoxes, function(box) {
5916                      if (!box.options.fullWidth) {
5917                          box.width = newMaxChartAreaWidth;
5918                      }
5919                  });
5920  
5921                  maxChartAreaHeight = newMaxChartAreaHeight;
5922                  maxChartAreaWidth = newMaxChartAreaWidth;
5923              }
5924  
5925              // Step 7 - Position the boxes

5926              var left = xPadding;
5927              var top = yPadding;
5928              var right = 0;
5929              var bottom = 0;
5930  
5931              helpers.each(leftBoxes.concat(topBoxes), placeBox);
5932  
5933              // Account for chart width and height

5934              left += maxChartAreaWidth;
5935              top += maxChartAreaHeight;
5936  
5937              helpers.each(rightBoxes, placeBox);
5938              helpers.each(bottomBoxes, placeBox);
5939  
5940  			function placeBox(box) {
5941                  if (box.isHorizontal()) {
5942                      box.left = box.options.fullWidth ? xPadding : totalLeftBoxesWidth;
5943                      box.right = box.options.fullWidth ? width - xPadding : totalLeftBoxesWidth + maxChartAreaWidth;
5944                      box.top = top;
5945                      box.bottom = top + box.height;
5946  
5947                      // Move to next point

5948                      top = box.bottom;
5949  
5950                  } else {
5951  
5952                      box.left = left;
5953                      box.right = left + box.width;
5954                      box.top = totalTopBoxesHeight;
5955                      box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
5956  
5957                      // Move to next point

5958                      left = box.right;
5959                  }
5960              }
5961  
5962              // Step 8

5963              chartInstance.chartArea = {
5964                  left: totalLeftBoxesWidth,
5965                  top: totalTopBoxesHeight,
5966                  right: totalLeftBoxesWidth + maxChartAreaWidth,
5967                  bottom: totalTopBoxesHeight + maxChartAreaHeight
5968              };
5969  
5970              // Step 9

5971              helpers.each(chartAreaBoxes, function(box) {
5972                  box.left = chartInstance.chartArea.left;
5973                  box.top = chartInstance.chartArea.top;
5974                  box.right = chartInstance.chartArea.right;
5975                  box.bottom = chartInstance.chartArea.bottom;
5976  
5977                  box.update(maxChartAreaWidth, maxChartAreaHeight);
5978              });
5979          }
5980      };
5981  };
5982  
5983  },{}],28:[function(require,module,exports){
5984  "use strict";
5985  
5986  module.exports = function(Chart) {
5987  
5988      var helpers = Chart.helpers;
5989      var noop = helpers.noop;
5990  
5991      Chart.defaults.global.legend = {
5992  
5993          display: true,
5994          position: 'top',
5995          fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes)
5996          reverse: false,
5997  
5998          // a callback that will handle

5999          onClick: function(e, legendItem) {
6000              var index = legendItem.datasetIndex;
6001              var ci = this.chart;
6002              var meta = ci.getDatasetMeta(index);
6003  
6004              // See controller.isDatasetVisible comment

6005              meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
6006  
6007              // We hid a dataset ... rerender the chart

6008              ci.update();
6009          },
6010  
6011          labels: {
6012              boxWidth: 40,
6013              padding: 10,
6014              // Generates labels shown in the legend

6015              // Valid properties to return:

6016              // text : text to display

6017              // fillStyle : fill of coloured box

6018              // strokeStyle: stroke of coloured box

6019              // hidden : if this legend item refers to a hidden item

6020              // lineCap : cap style for line

6021              // lineDash

6022              // lineDashOffset :

6023              // lineJoin :

6024              // lineWidth :

6025              generateLabels: function(chart) {
6026                  var data = chart.data;
6027                  return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
6028                      return {
6029                          text: dataset.label,
6030                          fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
6031                          hidden: !chart.isDatasetVisible(i),
6032                          lineCap: dataset.borderCapStyle,
6033                          lineDash: dataset.borderDash,
6034                          lineDashOffset: dataset.borderDashOffset,
6035                          lineJoin: dataset.borderJoinStyle,
6036                          lineWidth: dataset.borderWidth,
6037                          strokeStyle: dataset.borderColor,
6038  
6039                          // Below is extra data used for toggling the datasets

6040                          datasetIndex: i
6041                      };
6042                  }, this) : [];
6043              }
6044          }
6045      };
6046  
6047      Chart.Legend = Chart.Element.extend({
6048  
6049          initialize: function(config) {
6050              helpers.extend(this, config);
6051  
6052              // Contains hit boxes for each dataset (in dataset order)

6053              this.legendHitBoxes = [];
6054  
6055              // Are we in doughnut mode which has a different data type

6056              this.doughnutMode = false;
6057          },
6058  
6059          // These methods are ordered by lifecyle. Utilities then follow.

6060          // Any function defined here is inherited by all legend types.

6061          // Any function can be extended by the legend type

6062  
6063          beforeUpdate: noop,
6064          update: function(maxWidth, maxHeight, margins) {
6065              var me = this;
6066  
6067              // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)

6068              me.beforeUpdate();
6069  
6070              // Absorb the master measurements

6071              me.maxWidth = maxWidth;
6072              me.maxHeight = maxHeight;
6073              me.margins = margins;
6074  
6075              // Dimensions

6076              me.beforeSetDimensions();
6077              me.setDimensions();
6078              me.afterSetDimensions();
6079              // Labels

6080              me.beforeBuildLabels();
6081              me.buildLabels();
6082              me.afterBuildLabels();
6083  
6084              // Fit

6085              me.beforeFit();
6086              me.fit();
6087              me.afterFit();
6088              //

6089              me.afterUpdate();
6090  
6091              return me.minSize;
6092          },
6093          afterUpdate: noop,
6094  
6095          //

6096  
6097          beforeSetDimensions: noop,
6098          setDimensions: function() {
6099              var me = this;
6100              // Set the unconstrained dimension before label rotation

6101              if (me.isHorizontal()) {
6102                  // Reset position before calculating rotation

6103                  me.width = me.maxWidth;
6104                  me.left = 0;
6105                  me.right = me.width;
6106              } else {
6107                  me.height = me.maxHeight;
6108  
6109                  // Reset position before calculating rotation

6110                  me.top = 0;
6111                  me.bottom = me.height;
6112              }
6113  
6114              // Reset padding

6115              me.paddingLeft = 0;
6116              me.paddingTop = 0;
6117              me.paddingRight = 0;
6118              me.paddingBottom = 0;
6119  
6120              // Reset minSize

6121              me.minSize = {
6122                  width: 0,
6123                  height: 0
6124              };
6125          },
6126          afterSetDimensions: noop,
6127  
6128          //

6129  
6130          beforeBuildLabels: noop,
6131          buildLabels: function() {
6132              var me = this;
6133              me.legendItems = me.options.labels.generateLabels.call(me, me.chart);
6134              if(me.options.reverse){
6135                  me.legendItems.reverse();
6136              }
6137          },
6138          afterBuildLabels: noop,
6139  
6140          //

6141  
6142          beforeFit: noop,
6143          fit: function() {
6144              var me = this;
6145              var opts = me.options;
6146              var labelOpts = opts.labels;
6147              var display = opts.display;
6148  
6149              var ctx = me.ctx;
6150  
6151              var globalDefault = Chart.defaults.global,
6152                  itemOrDefault = helpers.getValueOrDefault,
6153                  fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
6154                  fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
6155                  fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
6156                  labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
6157  
6158              // Reset hit boxes

6159              var hitboxes = me.legendHitBoxes = [];
6160  
6161              var minSize = me.minSize;
6162              var isHorizontal = me.isHorizontal();
6163  
6164              if (isHorizontal) {
6165                  minSize.width = me.maxWidth; // fill all the width

6166                  minSize.height = display ? 10 : 0;
6167              } else {
6168                  minSize.width = display ? 10 : 0;
6169                  minSize.height = me.maxHeight; // fill all the height

6170              }
6171  
6172              // Increase sizes here

6173              if (display) {
6174                  ctx.font = labelFont;
6175  
6176                  if (isHorizontal) {
6177                      // Labels

6178  
6179                      // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one

6180                      var lineWidths = me.lineWidths = [0];
6181                      var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;
6182  
6183                      ctx.textAlign = "left";
6184                      ctx.textBaseline = 'top';
6185  
6186                      helpers.each(me.legendItems, function(legendItem, i) {
6187                          var width = labelOpts.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
6188                          if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
6189                              totalHeight += fontSize + (labelOpts.padding);
6190                              lineWidths[lineWidths.length] = me.left;
6191                          }
6192  
6193                          // Store the hitbox width and height here. Final position will be updated in `draw`

6194                          hitboxes[i] = {
6195                              left: 0,
6196                              top: 0,
6197                              width: width,
6198                              height: fontSize
6199                          };
6200  
6201                          lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
6202                      });
6203  
6204                      minSize.height += totalHeight;
6205  
6206                  } else {
6207                      var vPadding = labelOpts.padding;
6208                      var columnWidths = me.columnWidths = [];
6209                      var totalWidth = labelOpts.padding;
6210                      var currentColWidth = 0;
6211                      var currentColHeight = 0;
6212                      var itemHeight = fontSize + vPadding;
6213  
6214                      helpers.each(me.legendItems, function(legendItem, i) {
6215                          var itemWidth = labelOpts.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
6216  
6217                          // If too tall, go to new column

6218                          if (currentColHeight + itemHeight > minSize.height) {
6219                              totalWidth += currentColWidth + labelOpts.padding;
6220                              columnWidths.push(currentColWidth); // previous column width

6221  
6222                              currentColWidth = 0;
6223                              currentColHeight = 0;
6224                          }
6225  
6226                          // Get max width

6227                          currentColWidth = Math.max(currentColWidth, itemWidth);
6228                          currentColHeight += itemHeight;
6229  
6230                          // Store the hitbox width and height here. Final position will be updated in `draw`

6231                          hitboxes[i] = {
6232                              left: 0,
6233                              top: 0,
6234                              width: itemWidth,
6235                              height: fontSize
6236                          };
6237                      });
6238  
6239                      totalWidth += currentColWidth;
6240                      columnWidths.push(currentColWidth);
6241                      minSize.width += totalWidth;
6242                  }
6243              }
6244  
6245              me.width = minSize.width;
6246              me.height = minSize.height;
6247          },
6248          afterFit: noop,
6249  
6250          // Shared Methods

6251          isHorizontal: function() {
6252              return this.options.position === "top" || this.options.position === "bottom";
6253          },
6254  
6255          // Actualy draw the legend on the canvas

6256          draw: function() {
6257              var me = this;
6258              var opts = me.options;
6259              var labelOpts = opts.labels;
6260              var globalDefault = Chart.defaults.global,
6261                  lineDefault = globalDefault.elements.line,
6262                  legendWidth = me.width,
6263                  legendHeight = me.height,
6264                  lineWidths = me.lineWidths;
6265  
6266              if (opts.display) {
6267                  var ctx = me.ctx,
6268                      cursor,
6269                      itemOrDefault = helpers.getValueOrDefault,
6270                      fontColor = itemOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor),
6271                      fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
6272                      fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
6273                      fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
6274                      labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
6275  
6276                  // Canvas setup

6277                  ctx.textAlign = "left";
6278                  ctx.textBaseline = 'top';
6279                  ctx.lineWidth = 0.5;
6280                  ctx.strokeStyle = fontColor; // for strikethrough effect

6281                  ctx.fillStyle = fontColor; // render in correct colour

6282                  ctx.font = labelFont;
6283  
6284                  var boxWidth = labelOpts.boxWidth,
6285                      hitboxes = me.legendHitBoxes;
6286  
6287                  // current position

6288                  var drawLegendBox = function(x, y, legendItem) {
6289                      // Set the ctx for the box

6290                      ctx.save();
6291  
6292                      ctx.fillStyle = itemOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
6293                      ctx.lineCap = itemOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
6294                      ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
6295                      ctx.lineJoin = itemOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
6296                      ctx.lineWidth = itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
6297                      ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
6298  
6299                      if (ctx.setLineDash) {
6300                          // IE 9 and 10 do not support line dash

6301                          ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash));
6302                      }
6303  
6304                      // Draw the box

6305                      ctx.strokeRect(x, y, boxWidth, fontSize);
6306                      ctx.fillRect(x, y, boxWidth, fontSize);
6307  
6308                      ctx.restore();
6309                  };
6310                  var fillText = function(x, y, legendItem, textWidth) {
6311                      ctx.fillText(legendItem.text, boxWidth + (fontSize / 2) + x, y);
6312  
6313                      if (legendItem.hidden) {
6314                          // Strikethrough the text if hidden

6315                          ctx.beginPath();
6316                          ctx.lineWidth = 2;
6317                          ctx.moveTo(boxWidth + (fontSize / 2) + x, y + (fontSize / 2));
6318                          ctx.lineTo(boxWidth + (fontSize / 2) + x + textWidth, y + (fontSize / 2));
6319                          ctx.stroke();
6320                      }
6321                  };
6322  
6323                  // Horizontal

6324                  var isHorizontal = me.isHorizontal();
6325                  if (isHorizontal) {
6326                      cursor = {
6327                          x: me.left + ((legendWidth - lineWidths[0]) / 2),
6328                          y: me.top + labelOpts.padding,
6329                          line: 0
6330                      };
6331                  } else {
6332                      cursor = {
6333                          x: me.left + labelOpts.padding,
6334                          y: me.top,
6335                          line: 0
6336                      };
6337                  }
6338  
6339                  var itemHeight = fontSize + labelOpts.padding;
6340                  helpers.each(me.legendItems, function(legendItem, i) {
6341                      var textWidth = ctx.measureText(legendItem.text).width,
6342                          width = boxWidth + (fontSize / 2) + textWidth,
6343                          x = cursor.x,
6344                          y = cursor.y;
6345  
6346                      if (isHorizontal) {
6347                          if (x + width >= legendWidth) {
6348                              y = cursor.y += fontSize + (labelOpts.padding);
6349                              cursor.line++;
6350                              x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
6351                          }
6352                      } else {
6353                          if (y + itemHeight > me.bottom) {
6354                              x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
6355                              y = cursor.y = me.top;
6356                              cursor.line++;
6357                          }
6358                      }
6359                      
6360  
6361                      drawLegendBox(x, y, legendItem);
6362  
6363                      hitboxes[i].left = x;
6364                      hitboxes[i].top = y;
6365  
6366                      // Fill the actual label

6367                      fillText(x, y, legendItem, textWidth);
6368  
6369                      if (isHorizontal) {
6370                          cursor.x += width + (labelOpts.padding);
6371                      } else {
6372                          cursor.y += itemHeight;
6373                      }
6374                      
6375                  });
6376              }
6377          },
6378  
6379          // Handle an event

6380          handleEvent: function(e) {
6381              var me = this;
6382              var position = helpers.getRelativePosition(e, me.chart.chart),
6383                  x = position.x,
6384                  y = position.y,
6385                  opts = me.options;
6386  
6387              if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
6388                  // See if we are touching one of the dataset boxes

6389                  var lh = me.legendHitBoxes;
6390                  for (var i = 0; i < lh.length; ++i) {
6391                      var hitBox = lh[i];
6392  
6393                      if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
6394                          // Touching an element

6395                          if (opts.onClick) {
6396                              opts.onClick.call(me, e, me.legendItems[i]);
6397                          }
6398                          break;
6399                      }
6400                  }
6401              }
6402          }
6403      });
6404  
6405      // Register the legend plugin

6406      Chart.plugins.register({
6407          beforeInit: function(chartInstance) {
6408              var opts = chartInstance.options;
6409              var legendOpts = opts.legend;
6410  
6411              if (legendOpts) {
6412                  chartInstance.legend = new Chart.Legend({
6413                      ctx: chartInstance.chart.ctx,
6414                      options: legendOpts,
6415                      chart: chartInstance
6416                  });
6417  
6418                  Chart.layoutService.addBox(chartInstance, chartInstance.legend);
6419              }
6420          }
6421      });
6422  };
6423  
6424  },{}],29:[function(require,module,exports){
6425  "use strict";
6426  
6427  module.exports = function(Chart) {
6428  
6429      var noop = Chart.helpers.noop;
6430  
6431      /**

6432       * The plugin service singleton

6433       * @namespace Chart.plugins

6434       * @since 2.1.0

6435       */
6436      Chart.plugins = {
6437          _plugins: [],
6438  
6439          /**

6440           * Registers the given plugin(s) if not already registered.

6441           * @param {Array|Object} plugins plugin instance(s).

6442           */
6443          register: function(plugins) {
6444              var p = this._plugins;
6445              ([]).concat(plugins).forEach(function(plugin) {
6446                  if (p.indexOf(plugin) === -1) {
6447                      p.push(plugin);
6448                  }
6449              });
6450          },
6451  
6452          /**

6453           * Unregisters the given plugin(s) only if registered.

6454           * @param {Array|Object} plugins plugin instance(s).

6455           */
6456          unregister: function(plugins) {
6457              var p = this._plugins;
6458              ([]).concat(plugins).forEach(function(plugin) {
6459                  var idx = p.indexOf(plugin);
6460                  if (idx !== -1) {
6461                      p.splice(idx, 1);
6462                  }
6463              });
6464          },
6465  
6466          /**

6467           * Remove all registered p^lugins.

6468           * @since 2.1.5

6469           */
6470          clear: function() {
6471              this._plugins = [];
6472          },
6473  
6474          /**

6475           * Returns the number of registered plugins?

6476           * @returns {Number}

6477           * @since 2.1.5

6478           */
6479          count: function() {
6480              return this._plugins.length;
6481          },
6482  
6483          /**

6484           * Returns all registered plugin intances.

6485           * @returns {Array} array of plugin objects.

6486           * @since 2.1.5

6487           */
6488          getAll: function() {
6489              return this._plugins;
6490          },
6491  
6492          /**

6493           * Calls registered plugins on the specified extension, with the given args. This

6494           * method immediately returns as soon as a plugin explicitly returns false. The

6495           * returned value can be used, for instance, to interrupt the current action.

6496           * @param {String} extension the name of the plugin method to call (e.g. 'beforeUpdate').

6497           * @param {Array} [args] extra arguments to apply to the extension call.

6498           * @returns {Boolean} false if any of the plugins return false, else returns true.

6499           */
6500          notify: function(extension, args) {
6501              var plugins = this._plugins;
6502              var ilen = plugins.length;
6503              var i, plugin;
6504  
6505              for (i=0; i<ilen; ++i) {
6506                  plugin = plugins[i];
6507                  if (typeof plugin[extension] === 'function') {
6508                      if (plugin[extension].apply(plugin, args || []) === false) {
6509                          return false;
6510                      }
6511                  }
6512              }
6513  
6514              return true;
6515          }
6516      };
6517  
6518      /**

6519       * Plugin extension methods.

6520       * @interface Chart.PluginBase

6521       * @since 2.1.0

6522       */
6523      Chart.PluginBase = Chart.Element.extend({
6524          // Called at start of chart init

6525          beforeInit: noop,
6526  
6527          // Called at end of chart init

6528          afterInit: noop,
6529  
6530          // Called at start of update

6531          beforeUpdate: noop,
6532  
6533          // Called at end of update

6534          afterUpdate: noop,
6535  
6536          // Called at start of draw

6537          beforeDraw: noop,
6538  
6539          // Called at end of draw

6540          afterDraw: noop,
6541  
6542          // Called during destroy

6543          destroy: noop
6544      });
6545  
6546      /**

6547       * Provided for backward compatibility, use Chart.plugins instead

6548       * @namespace Chart.pluginService

6549       * @deprecated since version 2.1.5

6550       * @todo remove me at version 3

6551       */
6552      Chart.pluginService = Chart.plugins;
6553  };
6554  
6555  },{}],30:[function(require,module,exports){
6556  "use strict";
6557  
6558  module.exports = function(Chart) {
6559  
6560      var helpers = Chart.helpers;
6561  
6562      Chart.defaults.scale = {
6563          display: true,
6564          position: "left",
6565  
6566          // grid line settings

6567          gridLines: {
6568              display: true,
6569              color: "rgba(0, 0, 0, 0.1)",
6570              lineWidth: 1,
6571              drawBorder: true,
6572              drawOnChartArea: true,
6573              drawTicks: true,
6574              tickMarkLength: 10,
6575              zeroLineWidth: 1,
6576              zeroLineColor: "rgba(0,0,0,0.25)",
6577              offsetGridLines: false
6578          },
6579  
6580          // scale label

6581          scaleLabel: {
6582              // actual label

6583              labelString: '',
6584  
6585              // display property

6586              display: false
6587          },
6588  
6589          // label settings

6590          ticks: {
6591              beginAtZero: false,
6592              minRotation: 0,
6593              maxRotation: 50,
6594              mirror: false,
6595              padding: 10,
6596              reverse: false,
6597              display: true,
6598              autoSkip: true,
6599              autoSkipPadding: 0,
6600              labelOffset: 0,
6601              // We pass through arrays to be rendered as multiline labels, we convert Others to strings here.

6602              callback: function(value) {
6603                  return helpers.isArray(value) ? value : '' + value;
6604              }
6605          }
6606      };
6607  
6608      Chart.Scale = Chart.Element.extend({
6609  
6610          // These methods are ordered by lifecyle. Utilities then follow.

6611          // Any function defined here is inherited by all scale types.

6612          // Any function can be extended by the scale type

6613  
6614          beforeUpdate: function() {
6615              helpers.callCallback(this.options.beforeUpdate, [this]);
6616          },
6617          update: function(maxWidth, maxHeight, margins) {
6618              var me = this;
6619  
6620              // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)

6621              me.beforeUpdate();
6622  
6623              // Absorb the master measurements

6624              me.maxWidth = maxWidth;
6625              me.maxHeight = maxHeight;
6626              me.margins = helpers.extend({
6627                  left: 0,
6628                  right: 0,
6629                  top: 0,
6630                  bottom: 0
6631              }, margins);
6632  
6633              // Dimensions

6634              me.beforeSetDimensions();
6635              me.setDimensions();
6636              me.afterSetDimensions();
6637  
6638              // Data min/max

6639              me.beforeDataLimits();
6640              me.determineDataLimits();
6641              me.afterDataLimits();
6642  
6643              // Ticks

6644              me.beforeBuildTicks();
6645              me.buildTicks();
6646              me.afterBuildTicks();
6647  
6648              me.beforeTickToLabelConversion();
6649              me.convertTicksToLabels();
6650              me.afterTickToLabelConversion();
6651  
6652              // Tick Rotation

6653              me.beforeCalculateTickRotation();
6654              me.calculateTickRotation();
6655              me.afterCalculateTickRotation();
6656              // Fit

6657              me.beforeFit();
6658              me.fit();
6659              me.afterFit();
6660              //

6661              me.afterUpdate();
6662  
6663              return me.minSize;
6664  
6665          },
6666          afterUpdate: function() {
6667              helpers.callCallback(this.options.afterUpdate, [this]);
6668          },
6669  
6670          //

6671  
6672          beforeSetDimensions: function() {
6673              helpers.callCallback(this.options.beforeSetDimensions, [this]);
6674          },
6675          setDimensions: function() {
6676              var me = this;
6677              // Set the unconstrained dimension before label rotation

6678              if (me.isHorizontal()) {
6679                  // Reset position before calculating rotation

6680                  me.width = me.maxWidth;
6681                  me.left = 0;
6682                  me.right = me.width;
6683              } else {
6684                  me.height = me.maxHeight;
6685  
6686                  // Reset position before calculating rotation

6687                  me.top = 0;
6688                  me.bottom = me.height;
6689              }
6690  
6691              // Reset padding

6692              me.paddingLeft = 0;
6693              me.paddingTop = 0;
6694              me.paddingRight = 0;
6695              me.paddingBottom = 0;
6696          },
6697          afterSetDimensions: function() {
6698              helpers.callCallback(this.options.afterSetDimensions, [this]);
6699          },
6700  
6701          // Data limits

6702          beforeDataLimits: function() {
6703              helpers.callCallback(this.options.beforeDataLimits, [this]);
6704          },
6705          determineDataLimits: helpers.noop,
6706          afterDataLimits: function() {
6707              helpers.callCallback(this.options.afterDataLimits, [this]);
6708          },
6709  
6710          //

6711          beforeBuildTicks: function() {
6712              helpers.callCallback(this.options.beforeBuildTicks, [this]);
6713          },
6714          buildTicks: helpers.noop,
6715          afterBuildTicks: function() {
6716              helpers.callCallback(this.options.afterBuildTicks, [this]);
6717          },
6718  
6719          beforeTickToLabelConversion: function() {
6720              helpers.callCallback(this.options.beforeTickToLabelConversion, [this]);
6721          },
6722          convertTicksToLabels: function() {
6723              var me = this;
6724              // Convert ticks to strings

6725              me.ticks = me.ticks.map(function(numericalTick, index, ticks) {
6726                      if (me.options.ticks.userCallback) {
6727                          return me.options.ticks.userCallback(numericalTick, index, ticks);
6728                      }
6729                      return me.options.ticks.callback(numericalTick, index, ticks);
6730                  },
6731                  me);
6732          },
6733          afterTickToLabelConversion: function() {
6734              helpers.callCallback(this.options.afterTickToLabelConversion, [this]);
6735          },
6736  
6737          //

6738  
6739          beforeCalculateTickRotation: function() {
6740              helpers.callCallback(this.options.beforeCalculateTickRotation, [this]);
6741          },
6742          calculateTickRotation: function() {
6743              var me = this;
6744              var context = me.ctx;
6745              var globalDefaults = Chart.defaults.global;
6746              var optionTicks = me.options.ticks;
6747  
6748              //Get the width of each grid by calculating the difference

6749              //between x offsets between 0 and 1.

6750              var tickFontSize = helpers.getValueOrDefault(optionTicks.fontSize, globalDefaults.defaultFontSize);
6751              var tickFontStyle = helpers.getValueOrDefault(optionTicks.fontStyle, globalDefaults.defaultFontStyle);
6752              var tickFontFamily = helpers.getValueOrDefault(optionTicks.fontFamily, globalDefaults.defaultFontFamily);
6753              var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
6754              context.font = tickLabelFont;
6755  
6756              var firstWidth = context.measureText(me.ticks[0]).width;
6757              var lastWidth = context.measureText(me.ticks[me.ticks.length - 1]).width;
6758              var firstRotated;
6759  
6760              me.labelRotation = optionTicks.minRotation || 0;
6761              me.paddingRight = 0;
6762              me.paddingLeft = 0;
6763  
6764              if (me.options.display) {
6765                  if (me.isHorizontal()) {
6766                      me.paddingRight = lastWidth / 2 + 3;
6767                      me.paddingLeft = firstWidth / 2 + 3;
6768  
6769                      if (!me.longestTextCache) {
6770                          me.longestTextCache = {};
6771                      }
6772                      var originalLabelWidth = helpers.longestText(context, tickLabelFont, me.ticks, me.longestTextCache);
6773                      var labelWidth = originalLabelWidth;
6774                      var cosRotation;
6775                      var sinRotation;
6776  
6777                      // Allow 3 pixels x2 padding either side for label readability

6778                      // only the index matters for a dataset scale, but we want a consistent interface between scales

6779                      var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
6780  
6781                      //Max label rotation can be set or default to 90 - also act as a loop counter

6782                      while (labelWidth > tickWidth && me.labelRotation < optionTicks.maxRotation) {
6783                          cosRotation = Math.cos(helpers.toRadians(me.labelRotation));
6784                          sinRotation = Math.sin(helpers.toRadians(me.labelRotation));
6785  
6786                          firstRotated = cosRotation * firstWidth;
6787  
6788                          // We're right aligning the text now.

6789                          if (firstRotated + tickFontSize / 2 > me.yLabelWidth) {
6790                              me.paddingLeft = firstRotated + tickFontSize / 2;
6791                          }
6792  
6793                          me.paddingRight = tickFontSize / 2;
6794  
6795                          if (sinRotation * originalLabelWidth > me.maxHeight) {
6796                              // go back one step

6797                              me.labelRotation--;
6798                              break;
6799                          }
6800  
6801                          me.labelRotation++;
6802                          labelWidth = cosRotation * originalLabelWidth;
6803                      }
6804                  }
6805              }
6806  
6807              if (me.margins) {
6808                  me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
6809                  me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
6810              }
6811          },
6812          afterCalculateTickRotation: function() {
6813              helpers.callCallback(this.options.afterCalculateTickRotation, [this]);
6814          },
6815  
6816          //

6817  
6818          beforeFit: function() {
6819              helpers.callCallback(this.options.beforeFit, [this]);
6820          },
6821          fit: function() {
6822              var me = this;
6823              // Reset

6824              var minSize = me.minSize = {
6825                  width: 0,
6826                  height: 0
6827              };
6828  
6829              var opts = me.options;
6830              var globalDefaults = Chart.defaults.global;
6831              var tickOpts = opts.ticks;
6832              var scaleLabelOpts = opts.scaleLabel;
6833              var display = opts.display;
6834              var isHorizontal = me.isHorizontal();
6835  
6836              var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
6837              var tickFontStyle = helpers.getValueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
6838              var tickFontFamily = helpers.getValueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
6839              var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
6840  
6841              var scaleLabelFontSize = helpers.getValueOrDefault(scaleLabelOpts.fontSize, globalDefaults.defaultFontSize);
6842              var scaleLabelFontStyle = helpers.getValueOrDefault(scaleLabelOpts.fontStyle, globalDefaults.defaultFontStyle);
6843              var scaleLabelFontFamily = helpers.getValueOrDefault(scaleLabelOpts.fontFamily, globalDefaults.defaultFontFamily);
6844              var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily);
6845  
6846              var tickMarkLength = opts.gridLines.tickMarkLength;
6847  
6848              // Width

6849              if (isHorizontal) {
6850                  // subtract the margins to line up with the chartArea if we are a full width scale

6851                  minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
6852              } else {
6853                  minSize.width = display ? tickMarkLength : 0;
6854              }
6855  
6856              // height

6857              if (isHorizontal) {
6858                  minSize.height = display ? tickMarkLength : 0;
6859              } else {
6860                  minSize.height = me.maxHeight; // fill all the height

6861              }
6862  
6863              // Are we showing a title for the scale?

6864              if (scaleLabelOpts.display && display) {
6865                  if (isHorizontal) {
6866                      minSize.height += (scaleLabelFontSize * 1.5);
6867                  } else {
6868                      minSize.width += (scaleLabelFontSize * 1.5);
6869                  }
6870              }
6871  
6872              if (tickOpts.display && display) {
6873                  // Don't bother fitting the ticks if we are not showing them

6874                  if (!me.longestTextCache) {
6875                      me.longestTextCache = {};
6876                  }
6877  
6878                  var largestTextWidth = helpers.longestText(me.ctx, tickLabelFont, me.ticks, me.longestTextCache);
6879                  var tallestLabelHeightInLines = helpers.numberOfLabelLines(me.ticks);
6880                  var lineSpace = tickFontSize * 0.5;
6881  
6882                  if (isHorizontal) {
6883                      // A horizontal axis is more constrained by the height.

6884                      me.longestLabelWidth = largestTextWidth;
6885  
6886                      // TODO - improve this calculation

6887                      var labelHeight = (Math.sin(helpers.toRadians(me.labelRotation)) * me.longestLabelWidth) + (tickFontSize * tallestLabelHeightInLines) + (lineSpace * tallestLabelHeightInLines);
6888  
6889                      minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight);
6890                      me.ctx.font = tickLabelFont;
6891  
6892                      var firstLabelWidth = me.ctx.measureText(me.ticks[0]).width;
6893                      var lastLabelWidth = me.ctx.measureText(me.ticks[me.ticks.length - 1]).width;
6894  
6895                      // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated

6896                      // by the font height

6897                      var cosRotation = Math.cos(helpers.toRadians(me.labelRotation));
6898                      var sinRotation = Math.sin(helpers.toRadians(me.labelRotation));
6899                      me.paddingLeft = me.labelRotation !== 0 ? (cosRotation * firstLabelWidth) + 3 : firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges

6900                      me.paddingRight = me.labelRotation !== 0 ? (sinRotation * (tickFontSize / 2)) + 3 : lastLabelWidth / 2 + 3; // when rotated

6901                  } else {
6902                      // A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first

6903                      var maxLabelWidth = me.maxWidth - minSize.width;
6904  
6905                      // Account for padding

6906                      var mirror = tickOpts.mirror;
6907                      if (!mirror) {
6908                          largestTextWidth += me.options.ticks.padding;
6909                      } else {
6910                          // If mirrored text is on the inside so don't expand

6911                          largestTextWidth = 0;
6912                      }
6913  
6914                      if (largestTextWidth < maxLabelWidth) {
6915                          // We don't need all the room

6916                          minSize.width += largestTextWidth;
6917                      } else {
6918                          // Expand to max size

6919                          minSize.width = me.maxWidth;
6920                      }
6921  
6922                      me.paddingTop = tickFontSize / 2;
6923                      me.paddingBottom = tickFontSize / 2;
6924                  }
6925              }
6926  
6927              if (me.margins) {
6928                  me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
6929                  me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
6930                  me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
6931                  me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
6932              }
6933  
6934              me.width = minSize.width;
6935              me.height = minSize.height;
6936  
6937          },
6938          afterFit: function() {
6939              helpers.callCallback(this.options.afterFit, [this]);
6940          },
6941  
6942          // Shared Methods

6943          isHorizontal: function() {
6944              return this.options.position === "top" || this.options.position === "bottom";
6945          },
6946          isFullWidth: function() {
6947              return (this.options.fullWidth);
6948          },
6949  
6950          // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not

6951          getRightValue: function getRightValue(rawValue) {
6952              // Null and undefined values first

6953              if (rawValue === null || typeof(rawValue) === 'undefined') {
6954                  return NaN;
6955              }
6956              // isNaN(object) returns true, so make sure NaN is checking for a number

6957              if (typeof(rawValue) === 'number' && isNaN(rawValue)) {
6958                  return NaN;
6959              }
6960              // If it is in fact an object, dive in one more level

6961              if (typeof(rawValue) === "object") {
6962                  if ((rawValue instanceof Date) || (rawValue.isValid)) {
6963                      return rawValue;
6964                  } else {
6965                      return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
6966                  }
6967              }
6968  
6969              // Value is good, return it

6970              return rawValue;
6971          },
6972  
6973          // Used to get the value to display in the tooltip for the data at the given index

6974          // function getLabelForIndex(index, datasetIndex)

6975          getLabelForIndex: helpers.noop,
6976  
6977          // Used to get data value locations.  Value can either be an index or a numerical value

6978          getPixelForValue: helpers.noop,
6979  
6980          // Used to get the data value from a given pixel. This is the inverse of getPixelForValue

6981          getValueForPixel: helpers.noop,
6982  
6983          // Used for tick location, should

6984          getPixelForTick: function(index, includeOffset) {
6985              var me = this;
6986              if (me.isHorizontal()) {
6987                  var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
6988                  var tickWidth = innerWidth / Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
6989                  var pixel = (tickWidth * index) + me.paddingLeft;
6990  
6991                  if (includeOffset) {
6992                      pixel += tickWidth / 2;
6993                  }
6994  
6995                  var finalVal = me.left + Math.round(pixel);
6996                  finalVal += me.isFullWidth() ? me.margins.left : 0;
6997                  return finalVal;
6998              } else {
6999                  var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
7000                  return me.top + (index * (innerHeight / (me.ticks.length - 1)));
7001              }
7002          },
7003  
7004          // Utility for getting the pixel location of a percentage of scale

7005          getPixelForDecimal: function(decimal /*, includeOffset*/ ) {
7006              var me = this;
7007              if (me.isHorizontal()) {
7008                  var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
7009                  var valueOffset = (innerWidth * decimal) + me.paddingLeft;
7010  
7011                  var finalVal = me.left + Math.round(valueOffset);
7012                  finalVal += me.isFullWidth() ? me.margins.left : 0;
7013                  return finalVal;
7014              } else {
7015                  return me.top + (decimal * me.height);
7016              }
7017          },
7018  
7019          getBasePixel: function() {
7020              var me = this;
7021              var min = me.min;
7022              var max = me.max;
7023  
7024              return me.getPixelForValue(
7025                  me.beginAtZero? 0:
7026                  min < 0 && max < 0? max :
7027                  min > 0 && max > 0? min :
7028                  0);
7029          },
7030  
7031          // Actualy draw the scale on the canvas

7032          // @param {rectangle} chartArea : the area of the chart to draw full grid lines on

7033          draw: function(chartArea) {
7034              var me = this;
7035              var options = me.options;
7036              if (!options.display) {
7037                  return;
7038              }
7039  
7040              var context = me.ctx;
7041              var globalDefaults = Chart.defaults.global;
7042              var optionTicks = options.ticks;
7043              var gridLines = options.gridLines;
7044              var scaleLabel = options.scaleLabel;
7045  
7046              var isRotated = me.labelRotation !== 0;
7047              var skipRatio;
7048              var useAutoskipper = optionTicks.autoSkip;
7049              var isHorizontal = me.isHorizontal();
7050  
7051              // figure out the maximum number of gridlines to show

7052              var maxTicks;
7053              if (optionTicks.maxTicksLimit) {
7054                  maxTicks = optionTicks.maxTicksLimit;
7055              }
7056  
7057              var tickFontColor = helpers.getValueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
7058              var tickFontSize = helpers.getValueOrDefault(optionTicks.fontSize, globalDefaults.defaultFontSize);
7059              var tickFontStyle = helpers.getValueOrDefault(optionTicks.fontStyle, globalDefaults.defaultFontStyle);
7060              var tickFontFamily = helpers.getValueOrDefault(optionTicks.fontFamily, globalDefaults.defaultFontFamily);
7061              var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
7062              var tl = gridLines.tickMarkLength;
7063  
7064              var scaleLabelFontColor = helpers.getValueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
7065              var scaleLabelFontSize = helpers.getValueOrDefault(scaleLabel.fontSize, globalDefaults.defaultFontSize);
7066              var scaleLabelFontStyle = helpers.getValueOrDefault(scaleLabel.fontStyle, globalDefaults.defaultFontStyle);
7067              var scaleLabelFontFamily = helpers.getValueOrDefault(scaleLabel.fontFamily, globalDefaults.defaultFontFamily);
7068              var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily);
7069  
7070              var labelRotationRadians = helpers.toRadians(me.labelRotation);
7071              var cosRotation = Math.cos(labelRotationRadians);
7072              var sinRotation = Math.sin(labelRotationRadians);
7073              var longestRotatedLabel = me.longestLabelWidth * cosRotation;
7074              var rotatedLabelHeight = tickFontSize * sinRotation;
7075  
7076              // Make sure we draw text in the correct color and font

7077              context.fillStyle = tickFontColor;
7078  
7079              var itemsToDraw = [];
7080  
7081              if (isHorizontal) {
7082                  skipRatio = false;
7083  
7084                  // Only calculate the skip ratio with the half width of longestRotateLabel if we got an actual rotation

7085                  // See #2584

7086                  if (isRotated) {
7087                      longestRotatedLabel /= 2;
7088                  }
7089  
7090                  if ((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length > (me.width - (me.paddingLeft + me.paddingRight))) {
7091                      skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length) / (me.width - (me.paddingLeft + me.paddingRight)));
7092                  }
7093  
7094                  // if they defined a max number of optionTicks,

7095                  // increase skipRatio until that number is met

7096                  if (maxTicks && me.ticks.length > maxTicks) {
7097                      while (!skipRatio || me.ticks.length / (skipRatio || 1) > maxTicks) {
7098                          if (!skipRatio) {
7099                              skipRatio = 1;
7100                          }
7101                          skipRatio += 1;
7102                      }
7103                  }
7104  
7105                  if (!useAutoskipper) {
7106                      skipRatio = false;
7107                  }
7108              }
7109  
7110  
7111              var xTickStart = options.position === "right" ? me.left : me.right - tl;
7112              var xTickEnd = options.position === "right" ? me.left + tl : me.right;
7113              var yTickStart = options.position === "bottom" ? me.top : me.bottom - tl;
7114              var yTickEnd = options.position === "bottom" ? me.top + tl : me.bottom;
7115  
7116              helpers.each(me.ticks, function(label, index) {
7117                  // If the callback returned a null or undefined value, do not draw this line

7118                  if (label === undefined || label === null) {
7119                      return;
7120                  }
7121  
7122                  var isLastTick = me.ticks.length === index + 1;
7123  
7124                  // Since we always show the last tick,we need may need to hide the last shown one before

7125                  var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio >= me.ticks.length);
7126                  if (shouldSkip && !isLastTick || (label === undefined || label === null)) {
7127                      return;
7128                  }
7129  
7130                  var lineWidth, lineColor;
7131                  if (index === (typeof me.zeroLineIndex !== 'undefined' ? me.zeroLineIndex : 0)) {
7132                      // Draw the first index specially

7133                      lineWidth = gridLines.zeroLineWidth;
7134                      lineColor = gridLines.zeroLineColor;
7135                  } else  {
7136                      lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, index);
7137                      lineColor = helpers.getValueAtIndexOrDefault(gridLines.color, index);
7138                  }
7139  
7140                  // Common properties

7141                  var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
7142                  var textAlign, textBaseline = 'middle';
7143  
7144                  if (isHorizontal) {
7145                      if (!isRotated) {
7146                          textBaseline = options.position === 'top' ? 'bottom' : 'top';
7147                      }
7148  
7149                      textAlign = isRotated ? 'right' : 'center';
7150  
7151                      var xLineValue = me.getPixelForTick(index) + helpers.aliasPixel(lineWidth); // xvalues for grid lines

7152                      labelX = me.getPixelForTick(index, gridLines.offsetGridLines) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)

7153                      labelY = (isRotated) ? me.top + 12 : options.position === 'top' ? me.bottom - tl : me.top + tl;
7154  
7155                      tx1 = tx2 = x1 = x2 = xLineValue;
7156                      ty1 = yTickStart;
7157                      ty2 = yTickEnd;
7158                      y1 = chartArea.top;
7159                      y2 = chartArea.bottom;
7160                  } else {
7161                      if (options.position === 'left') {
7162                          if (optionTicks.mirror) {
7163                              labelX = me.right + optionTicks.padding;
7164                              textAlign = 'left';
7165                          } else {
7166                              labelX = me.right - optionTicks.padding;
7167                              textAlign = 'right';
7168                          }
7169                      } else {
7170                          // right side

7171                          if (optionTicks.mirror) {
7172                              labelX = me.left - optionTicks.padding;
7173                              textAlign = 'right';
7174                          } else {
7175                              labelX = me.left + optionTicks.padding;
7176                              textAlign = 'left';
7177                          }
7178                      }
7179  
7180                      var yLineValue = me.getPixelForTick(index); // xvalues for grid lines

7181                      yLineValue += helpers.aliasPixel(lineWidth);
7182                      labelY = me.getPixelForTick(index, gridLines.offsetGridLines);
7183  
7184                      tx1 = xTickStart;
7185                      tx2 = xTickEnd;
7186                      x1 = chartArea.left;
7187                      x2 = chartArea.right;
7188                      ty1 = ty2 = y1 = y2 = yLineValue;
7189                  }
7190  
7191                  itemsToDraw.push({
7192                      tx1: tx1,
7193                      ty1: ty1,
7194                      tx2: tx2,
7195                      ty2: ty2,
7196                      x1: x1,
7197                      y1: y1,
7198                      x2: x2,
7199                      y2: y2,
7200                      labelX: labelX,
7201                      labelY: labelY,
7202                      glWidth: lineWidth,
7203                      glColor: lineColor,
7204                      rotation: -1 * labelRotationRadians,
7205                      label: label,
7206                      textBaseline: textBaseline,
7207                      textAlign: textAlign
7208                  });
7209              });
7210  
7211              // Draw all of the tick labels, tick marks, and grid lines at the correct places

7212              helpers.each(itemsToDraw, function(itemToDraw) {
7213                  if (gridLines.display) {
7214                      context.lineWidth = itemToDraw.glWidth;
7215                      context.strokeStyle = itemToDraw.glColor;
7216  
7217                      context.beginPath();
7218  
7219                      if (gridLines.drawTicks) {
7220                          context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
7221                          context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
7222                      }
7223  
7224                      if (gridLines.drawOnChartArea) {
7225                          context.moveTo(itemToDraw.x1, itemToDraw.y1);
7226                          context.lineTo(itemToDraw.x2, itemToDraw.y2);
7227                      }
7228  
7229                      context.stroke();
7230                  }
7231  
7232                  if (optionTicks.display) {
7233                      context.save();
7234                      context.translate(itemToDraw.labelX, itemToDraw.labelY);
7235                      context.rotate(itemToDraw.rotation);
7236                      context.font = tickLabelFont;
7237                      context.textBaseline = itemToDraw.textBaseline;
7238                      context.textAlign = itemToDraw.textAlign;
7239  
7240                      var label = itemToDraw.label;
7241                      if (helpers.isArray(label)) {
7242                          for (var i = 0, y = 0; i < label.length; ++i) {
7243                              // We just make sure the multiline element is a string here..

7244                              context.fillText('' + label[i], 0, y);
7245                              // apply same lineSpacing as calculated @ L#320

7246                              y += (tickFontSize * 1.5);
7247                          }
7248                      } else {
7249                          context.fillText(label, 0, 0);
7250                      }
7251                      context.restore();
7252                  }
7253              });
7254  
7255              if (scaleLabel.display) {
7256                  // Draw the scale label

7257                  var scaleLabelX;
7258                  var scaleLabelY;
7259                  var rotation = 0;
7260  
7261                  if (isHorizontal) {
7262                      scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width

7263                      scaleLabelY = options.position === 'bottom' ? me.bottom - (scaleLabelFontSize / 2) : me.top + (scaleLabelFontSize / 2);
7264                  } else {
7265                      var isLeft = options.position === 'left';
7266                      scaleLabelX = isLeft ? me.left + (scaleLabelFontSize / 2) : me.right - (scaleLabelFontSize / 2);
7267                      scaleLabelY = me.top + ((me.bottom - me.top) / 2);
7268                      rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
7269                  }
7270                  
7271                  context.save();
7272                  context.translate(scaleLabelX, scaleLabelY);
7273                  context.rotate(rotation);
7274                  context.textAlign = 'center';
7275                  context.textBaseline = 'middle';
7276                  context.fillStyle = scaleLabelFontColor; // render in correct colour

7277                  context.font = scaleLabelFont;
7278                  context.fillText(scaleLabel.labelString, 0, 0);
7279                  context.restore();
7280              }
7281  
7282              if (gridLines.drawBorder) {
7283                  // Draw the line at the edge of the axis

7284                  context.lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, 0);
7285                  context.strokeStyle = helpers.getValueAtIndexOrDefault(gridLines.color, 0);
7286                  var x1 = me.left,
7287                      x2 = me.right,
7288                      y1 = me.top,
7289                      y2 = me.bottom;
7290  
7291                  var aliasPixel = helpers.aliasPixel(context.lineWidth);
7292                  if (isHorizontal) {
7293                      y1 = y2 = options.position === 'top' ? me.bottom : me.top;
7294                      y1 += aliasPixel;
7295                      y2 += aliasPixel;
7296                  } else {
7297                      x1 = x2 = options.position === 'left' ? me.right : me.left;
7298                      x1 += aliasPixel;
7299                      x2 += aliasPixel;
7300                  }
7301  
7302                  context.beginPath();
7303                  context.moveTo(x1, y1);
7304                  context.lineTo(x2, y2);
7305                  context.stroke();
7306              }
7307          }
7308      });
7309  };
7310  
7311  },{}],31:[function(require,module,exports){
7312  "use strict";
7313  
7314  module.exports = function(Chart) {
7315  
7316      var helpers = Chart.helpers;
7317  
7318      Chart.scaleService = {
7319          // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then

7320          // use the new chart options to grab the correct scale

7321          constructors: {},
7322          // Use a registration function so that we can move to an ES6 map when we no longer need to support

7323          // old browsers

7324  
7325          // Scale config defaults

7326          defaults: {},
7327          registerScaleType: function(type, scaleConstructor, defaults) {
7328              this.constructors[type] = scaleConstructor;
7329              this.defaults[type] = helpers.clone(defaults);
7330          },
7331          getScaleConstructor: function(type) {
7332              return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
7333          },
7334          getScaleDefaults: function(type) {
7335              // Return the scale defaults merged with the global settings so that we always use the latest ones

7336              return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
7337          },
7338          updateScaleDefaults: function(type, additions) {
7339              var defaults = this.defaults;
7340              if (defaults.hasOwnProperty(type)) {
7341                  defaults[type] = helpers.extend(defaults[type], additions);
7342              }
7343          },
7344          addScalesToLayout: function(chartInstance) {
7345              // Adds each scale to the chart.boxes array to be sized accordingly

7346              helpers.each(chartInstance.scales, function(scale) {
7347                  Chart.layoutService.addBox(chartInstance, scale);
7348              });
7349          }
7350      };
7351  };
7352  },{}],32:[function(require,module,exports){
7353  "use strict";
7354  
7355  module.exports = function(Chart) {
7356  
7357      var helpers = Chart.helpers;
7358  
7359      Chart.defaults.global.title = {
7360          display: false,
7361          position: 'top',
7362          fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes)
7363  
7364          fontStyle: 'bold',
7365          padding: 10,
7366  
7367          // actual title

7368          text: ''
7369      };
7370  
7371      var noop = helpers.noop;
7372      Chart.Title = Chart.Element.extend({
7373  
7374          initialize: function(config) {
7375              var me = this;
7376              helpers.extend(me, config);
7377              me.options = helpers.configMerge(Chart.defaults.global.title, config.options);
7378  
7379              // Contains hit boxes for each dataset (in dataset order)

7380              me.legendHitBoxes = [];
7381          },
7382  
7383          // These methods are ordered by lifecyle. Utilities then follow.

7384  
7385          beforeUpdate: function () {
7386              var chartOpts = this.chart.options;
7387              if (chartOpts && chartOpts.title) {
7388                  this.options = helpers.configMerge(Chart.defaults.global.title, chartOpts.title);
7389              }
7390          },
7391          update: function(maxWidth, maxHeight, margins) {
7392              var me = this;
7393  
7394              // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)

7395              me.beforeUpdate();
7396  
7397              // Absorb the master measurements

7398              me.maxWidth = maxWidth;
7399              me.maxHeight = maxHeight;
7400              me.margins = margins;
7401  
7402              // Dimensions

7403              me.beforeSetDimensions();
7404              me.setDimensions();
7405              me.afterSetDimensions();
7406              // Labels

7407              me.beforeBuildLabels();
7408              me.buildLabels();
7409              me.afterBuildLabels();
7410  
7411              // Fit

7412              me.beforeFit();
7413              me.fit();
7414              me.afterFit();
7415              //

7416              me.afterUpdate();
7417  
7418              return me.minSize;
7419  
7420          },
7421          afterUpdate: noop,
7422  
7423          //

7424  
7425          beforeSetDimensions: noop,
7426          setDimensions: function() {
7427              var me = this;
7428              // Set the unconstrained dimension before label rotation

7429              if (me.isHorizontal()) {
7430                  // Reset position before calculating rotation

7431                  me.width = me.maxWidth;
7432                  me.left = 0;
7433                  me.right = me.width;
7434              } else {
7435                  me.height = me.maxHeight;
7436  
7437                  // Reset position before calculating rotation

7438                  me.top = 0;
7439                  me.bottom = me.height;
7440              }
7441  
7442              // Reset padding

7443              me.paddingLeft = 0;
7444              me.paddingTop = 0;
7445              me.paddingRight = 0;
7446              me.paddingBottom = 0;
7447  
7448              // Reset minSize

7449              me.minSize = {
7450                  width: 0,
7451                  height: 0
7452              };
7453          },
7454          afterSetDimensions: noop,
7455  
7456          //

7457  
7458          beforeBuildLabels: noop,
7459          buildLabels: noop,
7460          afterBuildLabels: noop,
7461  
7462          //

7463  
7464          beforeFit: noop,
7465          fit: function() {
7466  
7467              var me = this,
7468                  ctx = me.ctx,
7469                  valueOrDefault = helpers.getValueOrDefault,
7470                  opts = me.options,
7471                  globalDefaults = Chart.defaults.global,
7472                  display = opts.display,
7473                  fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
7474                  minSize = me.minSize;
7475  
7476              if (me.isHorizontal()) {
7477                  minSize.width = me.maxWidth; // fill all the width

7478                  minSize.height = display ? fontSize + (opts.padding * 2) : 0;
7479              } else {
7480                  minSize.width = display ? fontSize + (opts.padding * 2) : 0;
7481                  minSize.height = me.maxHeight; // fill all the height

7482              }
7483  
7484              me.width = minSize.width;
7485              me.height = minSize.height;
7486  
7487          },
7488          afterFit: noop,
7489  
7490          // Shared Methods

7491          isHorizontal: function() {
7492              var pos = this.options.position;
7493              return pos === "top" || pos === "bottom";
7494          },
7495  
7496          // Actualy draw the title block on the canvas

7497          draw: function() {
7498              var me = this,
7499                  ctx = me.ctx,
7500                  valueOrDefault = helpers.getValueOrDefault,
7501                  opts = me.options,
7502                  globalDefaults = Chart.defaults.global;
7503  
7504              if (opts.display) {
7505                  var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
7506                      fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle),
7507                      fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily),
7508                      titleFont = helpers.fontString(fontSize, fontStyle, fontFamily),
7509                      rotation = 0,
7510                      titleX,
7511                      titleY,
7512                      top = me.top,
7513                      left = me.left,
7514                      bottom = me.bottom,
7515                      right = me.right;
7516  
7517                  ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour

7518                  ctx.font = titleFont;
7519  
7520                  // Horizontal

7521                  if (me.isHorizontal()) {
7522                      titleX = left + ((right - left) / 2); // midpoint of the width

7523                      titleY = top + ((bottom - top) / 2); // midpoint of the height

7524                  } else {
7525                      titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2);
7526                      titleY = top + ((bottom - top) / 2);
7527                      rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
7528                  }
7529  
7530                  ctx.save();
7531                  ctx.translate(titleX, titleY);
7532                  ctx.rotate(rotation);
7533                  ctx.textAlign = 'center';
7534                  ctx.textBaseline = 'middle';
7535                  ctx.fillText(opts.text, 0, 0);
7536                  ctx.restore();
7537              }
7538          }
7539      });
7540  
7541      // Register the title plugin

7542      Chart.plugins.register({
7543          beforeInit: function(chartInstance) {
7544              var opts = chartInstance.options;
7545              var titleOpts = opts.title;
7546  
7547              if (titleOpts) {
7548                  chartInstance.titleBlock = new Chart.Title({
7549                      ctx: chartInstance.chart.ctx,
7550                      options: titleOpts,
7551                      chart: chartInstance
7552                  });
7553  
7554                  Chart.layoutService.addBox(chartInstance, chartInstance.titleBlock);
7555              }
7556          }
7557      });
7558  };
7559  
7560  },{}],33:[function(require,module,exports){
7561  "use strict";
7562  
7563  module.exports = function(Chart) {
7564  
7565      var helpers = Chart.helpers;
7566  
7567      Chart.defaults.global.tooltips = {
7568          enabled: true,
7569          custom: null,
7570          mode: 'single',
7571          backgroundColor: "rgba(0,0,0,0.8)",
7572          titleFontStyle: "bold",
7573          titleSpacing: 2,
7574          titleMarginBottom: 6,
7575          titleFontColor: "#fff",
7576          titleAlign: "left",
7577          bodySpacing: 2,
7578          bodyFontColor: "#fff",
7579          bodyAlign: "left",
7580          footerFontStyle: "bold",
7581          footerSpacing: 2,
7582          footerMarginTop: 6,
7583          footerFontColor: "#fff",
7584          footerAlign: "left",
7585          yPadding: 6,
7586          xPadding: 6,
7587          yAlign : 'center',
7588          xAlign : 'center',
7589          caretSize: 5,
7590          cornerRadius: 6,
7591          multiKeyBackground: '#fff',
7592          callbacks: {
7593              // Args are: (tooltipItems, data)

7594              beforeTitle: helpers.noop,
7595              title: function(tooltipItems, data) {
7596                  // Pick first xLabel for now

7597                  var title = '';
7598                  var labels = data.labels;
7599                  var labelCount = labels ? labels.length : 0;
7600  
7601                  if (tooltipItems.length > 0) {
7602                      var item = tooltipItems[0];
7603  
7604                      if (item.xLabel) {
7605                          title = item.xLabel;
7606                      } else if (labelCount > 0 && item.index < labelCount) {
7607                          title = labels[item.index];
7608                      }
7609                  }
7610  
7611                  return title;
7612              },
7613              afterTitle: helpers.noop,
7614  
7615              // Args are: (tooltipItems, data)

7616              beforeBody: helpers.noop,
7617  
7618              // Args are: (tooltipItem, data)

7619              beforeLabel: helpers.noop,
7620              label: function(tooltipItem, data) {
7621                  var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
7622                  return datasetLabel + ': ' + tooltipItem.yLabel;
7623              },
7624              labelColor: function(tooltipItem, chartInstance) {
7625                  var meta = chartInstance.getDatasetMeta(tooltipItem.datasetIndex);
7626                  var activeElement = meta.data[tooltipItem.index];
7627                  var view = activeElement._view;
7628                  return {
7629                      borderColor: view.borderColor,
7630                      backgroundColor: view.backgroundColor
7631                  };
7632              },
7633              afterLabel: helpers.noop,
7634  
7635              // Args are: (tooltipItems, data)

7636              afterBody: helpers.noop,
7637  
7638              // Args are: (tooltipItems, data)

7639              beforeFooter: helpers.noop,
7640              footer: helpers.noop,
7641              afterFooter: helpers.noop
7642          }
7643      };
7644  
7645      // Helper to push or concat based on if the 2nd parameter is an array or not

7646  	function pushOrConcat(base, toPush) {
7647          if (toPush) {
7648              if (helpers.isArray(toPush)) {
7649                  //base = base.concat(toPush);

7650                  Array.prototype.push.apply(base, toPush);
7651              } else {
7652                  base.push(toPush);
7653              }
7654          }
7655  
7656          return base;
7657      }
7658  
7659  	function getAveragePosition(elements) {
7660          if (!elements.length) {
7661              return false;
7662          }
7663  
7664          var i, len;
7665          var xPositions = [];
7666          var yPositions = [];
7667  
7668          for (i = 0, len = elements.length; i < len; ++i) {
7669              var el = elements[i];
7670              if (el && el.hasValue()){
7671                  var pos = el.tooltipPosition();
7672                  xPositions.push(pos.x);
7673                  yPositions.push(pos.y);
7674              }
7675          }
7676  
7677          var x = 0,
7678              y = 0;
7679          for (i = 0, len - xPositions.length; i < len; ++i) {
7680              x += xPositions[i];
7681              y += yPositions[i];
7682          }
7683  
7684          return {
7685              x: Math.round(x / xPositions.length),
7686              y: Math.round(y / xPositions.length)
7687          };
7688      }
7689  
7690      // Private helper to create a tooltip iteam model

7691      // @param element : the chart element (point, arc, bar) to create the tooltip item for

7692      // @return : new tooltip item

7693  	function createTooltipItem(element) {
7694          var xScale = element._xScale;
7695          var yScale = element._yScale || element._scale; // handle radar || polarArea charts

7696          var index = element._index,
7697              datasetIndex = element._datasetIndex;
7698  
7699          return {
7700              xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
7701              yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
7702              index: index,
7703              datasetIndex: datasetIndex
7704          };
7705      }
7706  
7707      Chart.Tooltip = Chart.Element.extend({
7708          initialize: function() {
7709              var me = this;
7710              var globalDefaults = Chart.defaults.global;
7711              var tooltipOpts = me._options;
7712              var getValueOrDefault = helpers.getValueOrDefault;
7713  
7714              helpers.extend(me, {
7715                  _model: {
7716                      // Positioning

7717                      xPadding: tooltipOpts.xPadding,
7718                      yPadding: tooltipOpts.yPadding,
7719                      xAlign : tooltipOpts.yAlign,
7720                      yAlign : tooltipOpts.xAlign,
7721  
7722                      // Body

7723                      bodyFontColor: tooltipOpts.bodyFontColor,
7724                      _bodyFontFamily: getValueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
7725                      _bodyFontStyle: getValueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
7726                      _bodyAlign: tooltipOpts.bodyAlign,
7727                      bodyFontSize: getValueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
7728                      bodySpacing: tooltipOpts.bodySpacing,
7729  
7730                      // Title

7731                      titleFontColor: tooltipOpts.titleFontColor,
7732                      _titleFontFamily: getValueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
7733                      _titleFontStyle: getValueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
7734                      titleFontSize: getValueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
7735                      _titleAlign: tooltipOpts.titleAlign,
7736                      titleSpacing: tooltipOpts.titleSpacing,
7737                      titleMarginBottom: tooltipOpts.titleMarginBottom,
7738  
7739                      // Footer

7740                      footerFontColor: tooltipOpts.footerFontColor,
7741                      _footerFontFamily: getValueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
7742                      _footerFontStyle: getValueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
7743                      footerFontSize: getValueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
7744                      _footerAlign: tooltipOpts.footerAlign,
7745                      footerSpacing: tooltipOpts.footerSpacing,
7746                      footerMarginTop: tooltipOpts.footerMarginTop,
7747  
7748                      // Appearance

7749                      caretSize: tooltipOpts.caretSize,
7750                      cornerRadius: tooltipOpts.cornerRadius,
7751                      backgroundColor: tooltipOpts.backgroundColor,
7752                      opacity: 0,
7753                      legendColorBackground: tooltipOpts.multiKeyBackground
7754                  }
7755              });
7756          },
7757  
7758          // Get the title

7759          // Args are: (tooltipItem, data)

7760          getTitle: function() {
7761              var me = this;
7762              var opts = me._options;
7763              var callbacks = opts.callbacks;
7764  
7765              var beforeTitle = callbacks.beforeTitle.apply(me, arguments),
7766                  title = callbacks.title.apply(me, arguments),
7767                  afterTitle = callbacks.afterTitle.apply(me, arguments);
7768  
7769              var lines = [];
7770              lines = pushOrConcat(lines, beforeTitle);
7771              lines = pushOrConcat(lines, title);
7772              lines = pushOrConcat(lines, afterTitle);
7773  
7774              return lines;
7775          },
7776  
7777          // Args are: (tooltipItem, data)

7778          getBeforeBody: function() {
7779              var lines = this._options.callbacks.beforeBody.apply(this, arguments);
7780              return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
7781          },
7782  
7783          // Args are: (tooltipItem, data)

7784          getBody: function(tooltipItems, data) {
7785              var me = this;
7786              var callbacks = me._options.callbacks;
7787              var bodyItems = [];
7788  
7789              helpers.each(tooltipItems, function(tooltipItem) {
7790                  var bodyItem = {
7791                      before: [],
7792                      lines: [],
7793                      after: []
7794                  };
7795                  pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
7796                  pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
7797                  pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
7798  
7799                  bodyItems.push(bodyItem);
7800              });
7801  
7802              return bodyItems;
7803          },
7804  
7805          // Args are: (tooltipItem, data)

7806          getAfterBody: function() {
7807              var lines = this._options.callbacks.afterBody.apply(this, arguments);
7808              return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
7809          },
7810  
7811          // Get the footer and beforeFooter and afterFooter lines

7812          // Args are: (tooltipItem, data)

7813          getFooter: function() {
7814              var me = this;
7815              var callbacks = me._options.callbacks;
7816  
7817              var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
7818              var footer = callbacks.footer.apply(me, arguments);
7819              var afterFooter = callbacks.afterFooter.apply(me, arguments);
7820  
7821              var lines = [];
7822              lines = pushOrConcat(lines, beforeFooter);
7823              lines = pushOrConcat(lines, footer);
7824              lines = pushOrConcat(lines, afterFooter);
7825  
7826              return lines;
7827          },
7828  
7829          update: function(changed) {
7830              var me = this;
7831              var opts = me._options;
7832              var model = me._model;
7833              var active = me._active;
7834  
7835              var data = me._data;
7836              var chartInstance = me._chartInstance;
7837  
7838              var i, len;
7839  
7840              if (active.length) {
7841                  model.opacity = 1;
7842  
7843                  var labelColors = [],
7844                      tooltipPosition = getAveragePosition(active);
7845  
7846                  var tooltipItems = [];
7847                  for (i = 0, len = active.length; i < len; ++i) {
7848                      tooltipItems.push(createTooltipItem(active[i]));
7849                  }
7850  
7851                  // If the user provided a sorting function, use it to modify the tooltip items

7852                  if (opts.itemSort) {
7853                      tooltipItems = tooltipItems.sort(opts.itemSort);
7854                  }
7855  
7856                  // If there is more than one item, show color items

7857                  if (active.length > 1) {
7858                      helpers.each(tooltipItems, function(tooltipItem) {
7859                          labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, chartInstance));
7860                      });
7861                  }
7862  
7863                  // Build the Text Lines

7864                  helpers.extend(model, {
7865                      title: me.getTitle(tooltipItems, data),
7866                      beforeBody: me.getBeforeBody(tooltipItems, data),
7867                      body: me.getBody(tooltipItems, data),
7868                      afterBody: me.getAfterBody(tooltipItems, data),
7869                      footer: me.getFooter(tooltipItems, data),
7870                      x: Math.round(tooltipPosition.x),
7871                      y: Math.round(tooltipPosition.y),
7872                      caretPadding: helpers.getValueOrDefault(tooltipPosition.padding, 2),
7873                      labelColors: labelColors
7874                  });
7875  
7876                  // We need to determine alignment of

7877                  var tooltipSize = me.getTooltipSize(model);
7878                  me.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas

7879  
7880                  helpers.extend(model, me.getBackgroundPoint(model, tooltipSize));
7881              } else {
7882                  me._model.opacity = 0;
7883              }
7884  
7885              if (changed && opts.custom) {
7886                  opts.custom.call(me, model);
7887              }
7888  
7889              return me;
7890          },
7891          getTooltipSize: function getTooltipSize(vm) {
7892              var ctx = this._chart.ctx;
7893  
7894              var size = {
7895                  height: vm.yPadding * 2, // Tooltip Padding
7896                  width: 0
7897              };
7898  
7899              // Count of all lines in the body

7900              var body = vm.body;
7901              var combinedBodyLength = body.reduce(function(count, bodyItem) {
7902                  return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
7903              }, 0);
7904              combinedBodyLength += vm.beforeBody.length + vm.afterBody.length;
7905  
7906              var titleLineCount = vm.title.length;
7907              var footerLineCount = vm.footer.length;
7908              var titleFontSize = vm.titleFontSize,
7909                  bodyFontSize = vm.bodyFontSize,
7910                  footerFontSize = vm.footerFontSize;
7911  
7912              size.height += titleLineCount * titleFontSize; // Title Lines

7913              size.height += (titleLineCount - 1) * vm.titleSpacing; // Title Line Spacing

7914              size.height += titleLineCount ? vm.titleMarginBottom : 0; // Title's bottom Margin

7915              size.height += combinedBodyLength * bodyFontSize; // Body Lines

7916              size.height += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing

7917              size.height += footerLineCount ? vm.footerMarginTop : 0; // Footer Margin

7918              size.height += footerLineCount * (footerFontSize); // Footer Lines

7919              size.height += footerLineCount ? (footerLineCount - 1) * vm.footerSpacing : 0; // Footer Line Spacing

7920  
7921              // Title width

7922              var widthPadding = 0;
7923              var maxLineWidth = function(line) {
7924                  size.width = Math.max(size.width, ctx.measureText(line).width + widthPadding);
7925              };
7926  
7927              ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
7928              helpers.each(vm.title, maxLineWidth);
7929  
7930              // Body width

7931              ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
7932              helpers.each(vm.beforeBody.concat(vm.afterBody), maxLineWidth);
7933  
7934              // Body lines may include some extra width due to the color box

7935              widthPadding = body.length > 1 ? (bodyFontSize + 2) : 0;
7936              helpers.each(body, function(bodyItem) {
7937                  helpers.each(bodyItem.before, maxLineWidth);
7938                  helpers.each(bodyItem.lines, maxLineWidth);
7939                  helpers.each(bodyItem.after, maxLineWidth);
7940              });
7941  
7942              // Reset back to 0

7943              widthPadding = 0;
7944  
7945              // Footer width

7946              ctx.font = helpers.fontString(footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
7947              helpers.each(vm.footer, maxLineWidth);
7948  
7949              // Add padding

7950              size.width += 2 * vm.xPadding;
7951  
7952              return size;
7953          },
7954          determineAlignment: function determineAlignment(size) {
7955              var me = this;
7956              var model = me._model;
7957              var chart = me._chart;
7958              var chartArea = me._chartInstance.chartArea;
7959  
7960              if (model.y < size.height) {
7961                  model.yAlign = 'top';
7962              } else if (model.y > (chart.height - size.height)) {
7963                  model.yAlign = 'bottom';
7964              }
7965  
7966              var lf, rf; // functions to determine left, right alignment

7967              var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart

7968              var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges

7969              var midX = (chartArea.left + chartArea.right) / 2;
7970              var midY = (chartArea.top + chartArea.bottom) / 2;
7971  
7972              if (model.yAlign === 'center') {
7973                  lf = function(x) {
7974                      return x <= midX;
7975                  };
7976                  rf = function(x) {
7977                      return x > midX;
7978                  };
7979              } else {
7980                  lf = function(x) {
7981                      return x <= (size.width / 2);
7982                  };
7983                  rf = function(x) {
7984                      return x >= (chart.width - (size.width / 2));
7985                  };
7986              }
7987  
7988              olf = function(x) {
7989                  return x + size.width > chart.width;
7990              };
7991              orf = function(x) {
7992                  return x - size.width < 0;
7993              };
7994              yf = function(y) {
7995                  return y <= midY ? 'top' : 'bottom';
7996              };
7997  
7998              if (lf(model.x)) {
7999                  model.xAlign = 'left';
8000  
8001                  // Is tooltip too wide and goes over the right side of the chart.?

8002                  if (olf(model.x)) {
8003                      model.xAlign = 'center';
8004                      model.yAlign = yf(model.y);
8005                  }
8006              } else if (rf(model.x)) {
8007                  model.xAlign = 'right';
8008  
8009                  // Is tooltip too wide and goes outside left edge of canvas?

8010                  if (orf(model.x)) {
8011                      model.xAlign = 'center';
8012                      model.yAlign = yf(model.y);
8013                  }
8014              }
8015          },
8016          getBackgroundPoint: function getBackgroundPoint(vm, size) {
8017              // Background Position

8018              var pt = {
8019                  x: vm.x,
8020                  y: vm.y
8021              };
8022  
8023              var caretSize = vm.caretSize,
8024                  caretPadding = vm.caretPadding,
8025                  cornerRadius = vm.cornerRadius,
8026                  xAlign = vm.xAlign,
8027                  yAlign = vm.yAlign,
8028                  paddingAndSize = caretSize + caretPadding,
8029                  radiusAndPadding = cornerRadius + caretPadding;
8030  
8031              if (xAlign === 'right') {
8032                  pt.x -= size.width;
8033              } else if (xAlign === 'center') {
8034                  pt.x -= (size.width / 2);
8035              }
8036  
8037              if (yAlign === 'top') {
8038                  pt.y += paddingAndSize;
8039              } else if (yAlign === 'bottom') {
8040                  pt.y -= size.height + paddingAndSize;
8041              } else {
8042                  pt.y -= (size.height / 2);
8043              }
8044  
8045              if (yAlign === 'center') {
8046                  if (xAlign === 'left') {
8047                      pt.x += paddingAndSize;
8048                  } else if (xAlign === 'right') {
8049                      pt.x -= paddingAndSize;
8050                  }
8051              } else {
8052                  if (xAlign === 'left') {
8053                      pt.x -= radiusAndPadding;
8054                  } else if (xAlign === 'right') {
8055                      pt.x += radiusAndPadding;
8056                  }
8057              }
8058  
8059              return pt;
8060          },
8061          drawCaret: function drawCaret(tooltipPoint, size, opacity, caretPadding) {
8062              var vm = this._view;
8063              var ctx = this._chart.ctx;
8064              var x1, x2, x3;
8065              var y1, y2, y3;
8066              var caretSize = vm.caretSize;
8067              var cornerRadius = vm.cornerRadius;
8068              var xAlign = vm.xAlign,
8069                  yAlign = vm.yAlign;
8070              var ptX = tooltipPoint.x,
8071                  ptY = tooltipPoint.y;
8072              var width = size.width,
8073                  height = size.height;
8074  
8075              if (yAlign === 'center') {
8076                  // Left or right side

8077                  if (xAlign === 'left') {
8078                      x1 = ptX;
8079                      x2 = x1 - caretSize;
8080                      x3 = x1;
8081                  } else {
8082                      x1 = ptX + width;
8083                      x2 = x1 + caretSize;
8084                      x3 = x1;
8085                  }
8086  
8087                  y2 = ptY + (height / 2);
8088                  y1 = y2 - caretSize;
8089                  y3 = y2 + caretSize;
8090              } else {
8091                  if (xAlign === 'left') {
8092                      x1 = ptX + cornerRadius;
8093                      x2 = x1 + caretSize;
8094                      x3 = x2 + caretSize;
8095                  } else if (xAlign === 'right') {
8096                      x1 = ptX + width - cornerRadius;
8097                      x2 = x1 - caretSize;
8098                      x3 = x2 - caretSize;
8099                  } else {
8100                      x2 = ptX + (width / 2);
8101                      x1 = x2 - caretSize;
8102                      x3 = x2 + caretSize;
8103                  }
8104  
8105                  if (yAlign === 'top') {
8106                      y1 = ptY;
8107                      y2 = y1 - caretSize;
8108                      y3 = y1;
8109                  } else {
8110                      y1 = ptY + height;
8111                      y2 = y1 + caretSize;
8112                      y3 = y1;
8113                  }
8114              }
8115  
8116              var bgColor = helpers.color(vm.backgroundColor);
8117              ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
8118              ctx.beginPath();
8119              ctx.moveTo(x1, y1);
8120              ctx.lineTo(x2, y2);
8121              ctx.lineTo(x3, y3);
8122              ctx.closePath();
8123              ctx.fill();
8124          },
8125          drawTitle: function drawTitle(pt, vm, ctx, opacity) {
8126              var title = vm.title;
8127  
8128              if (title.length) {
8129                  ctx.textAlign = vm._titleAlign;
8130                  ctx.textBaseline = "top";
8131  
8132                  var titleFontSize = vm.titleFontSize,
8133                      titleSpacing = vm.titleSpacing;
8134  
8135                  var titleFontColor = helpers.color(vm.titleFontColor);
8136                  ctx.fillStyle = titleFontColor.alpha(opacity * titleFontColor.alpha()).rgbString();
8137                  ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
8138  
8139                  var i, len;
8140                  for (i = 0, len = title.length; i < len; ++i) {
8141                      ctx.fillText(title[i], pt.x, pt.y);
8142                      pt.y += titleFontSize + titleSpacing; // Line Height and spacing

8143  
8144                      if (i + 1 === title.length) {
8145                          pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing

8146                      }
8147                  }
8148              }
8149          },
8150          drawBody: function drawBody(pt, vm, ctx, opacity) {
8151              var bodyFontSize = vm.bodyFontSize;
8152              var bodySpacing = vm.bodySpacing;
8153              var body = vm.body;
8154  
8155              ctx.textAlign = vm._bodyAlign;
8156              ctx.textBaseline = "top";
8157  
8158              var bodyFontColor = helpers.color(vm.bodyFontColor);
8159              var textColor = bodyFontColor.alpha(opacity * bodyFontColor.alpha()).rgbString();
8160              ctx.fillStyle = textColor;
8161              ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
8162  
8163              // Before Body

8164              var xLinePadding = 0;
8165              var fillLineOfText = function(line) {
8166                  ctx.fillText(line, pt.x + xLinePadding, pt.y);
8167                  pt.y += bodyFontSize + bodySpacing;
8168              };
8169  
8170              // Before body lines

8171              helpers.each(vm.beforeBody, fillLineOfText);
8172  
8173              var drawColorBoxes = body.length > 1;
8174              xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
8175  
8176              // Draw body lines now

8177              helpers.each(body, function(bodyItem, i) {
8178                  helpers.each(bodyItem.before, fillLineOfText);
8179  
8180                  helpers.each(bodyItem.lines, function(line) {
8181                      // Draw Legend-like boxes if needed

8182                      if (drawColorBoxes) {
8183                          // Fill a white rect so that colours merge nicely if the opacity is < 1

8184                          ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString();
8185                          ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
8186  
8187                          // Border

8188                          ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
8189                          ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
8190  
8191                          // Inner square

8192                          ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
8193                          ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
8194  
8195                          ctx.fillStyle = textColor;
8196                      }
8197  
8198                      fillLineOfText(line);
8199                  });
8200  
8201                  helpers.each(bodyItem.after, fillLineOfText);
8202              });
8203  
8204              // Reset back to 0 for after body

8205              xLinePadding = 0;
8206  
8207              // After body lines

8208              helpers.each(vm.afterBody, fillLineOfText);
8209              pt.y -= bodySpacing; // Remove last body spacing

8210          },
8211          drawFooter: function drawFooter(pt, vm, ctx, opacity) {
8212              var footer = vm.footer;
8213  
8214              if (footer.length) {
8215                  pt.y += vm.footerMarginTop;
8216  
8217                  ctx.textAlign = vm._footerAlign;
8218                  ctx.textBaseline = "top";
8219  
8220                  var footerFontColor = helpers.color(vm.footerFontColor);
8221                  ctx.fillStyle = footerFontColor.alpha(opacity * footerFontColor.alpha()).rgbString();
8222                  ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
8223  
8224                  helpers.each(footer, function(line) {
8225                      ctx.fillText(line, pt.x, pt.y);
8226                      pt.y += vm.footerFontSize + vm.footerSpacing;
8227                  });
8228              }
8229          },
8230          draw: function draw() {
8231              var ctx = this._chart.ctx;
8232              var vm = this._view;
8233  
8234              if (vm.opacity === 0) {
8235                  return;
8236              }
8237  
8238              var tooltipSize = this.getTooltipSize(vm);
8239              var pt = {
8240                  x: vm.x,
8241                  y: vm.y
8242              };
8243  
8244              // IE11/Edge does not like very small opacities, so snap to 0

8245              var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
8246  
8247              if (this._options.enabled) {
8248                  // Draw Background

8249                  var bgColor = helpers.color(vm.backgroundColor);
8250                  ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
8251                  helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius);
8252                  ctx.fill();
8253  
8254                  // Draw Caret

8255                  this.drawCaret(pt, tooltipSize, opacity, vm.caretPadding);
8256  
8257                  // Draw Title, Body, and Footer

8258                  pt.x += vm.xPadding;
8259                  pt.y += vm.yPadding;
8260  
8261                  // Titles

8262                  this.drawTitle(pt, vm, ctx, opacity);
8263  
8264                  // Body

8265                  this.drawBody(pt, vm, ctx, opacity);
8266  
8267                  // Footer

8268                  this.drawFooter(pt, vm, ctx, opacity);
8269              }
8270          }
8271      });
8272  };
8273  
8274  },{}],34:[function(require,module,exports){
8275  "use strict";
8276  
8277  module.exports = function(Chart, moment) {
8278  
8279    var helpers = Chart.helpers,
8280      globalOpts = Chart.defaults.global;
8281  
8282    globalOpts.elements.arc = {
8283      backgroundColor: globalOpts.defaultColor,
8284      borderColor: "#fff",
8285      borderWidth: 2
8286    };
8287  
8288    Chart.elements.Arc = Chart.Element.extend({
8289      inLabelRange: function(mouseX) {
8290        var vm = this._view;
8291  
8292        if (vm) {
8293          return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
8294        } else {
8295          return false;
8296        }
8297      },
8298      inRange: function(chartX, chartY) {
8299        var vm = this._view;
8300  
8301        if (vm) {
8302          var pointRelativePosition = helpers.getAngleFromPoint(vm, {
8303              x: chartX,
8304              y: chartY
8305            }),
8306            angle = pointRelativePosition.angle,
8307            distance = pointRelativePosition.distance;
8308  
8309          //Sanitise angle range

8310          var startAngle = vm.startAngle;
8311          var endAngle = vm.endAngle;
8312          while (endAngle < startAngle) {
8313            endAngle += 2.0 * Math.PI;
8314          }
8315          while (angle > endAngle) {
8316            angle -= 2.0 * Math.PI;
8317          }
8318          while (angle < startAngle) {
8319            angle += 2.0 * Math.PI;
8320          }
8321  
8322          //Check if within the range of the open/close angle

8323          var betweenAngles = (angle >= startAngle && angle <= endAngle),
8324            withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
8325  
8326          return (betweenAngles && withinRadius);
8327        } else {
8328          return false;
8329        }
8330      },
8331      tooltipPosition: function() {
8332        var vm = this._view;
8333  
8334        var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
8335          rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
8336        return {
8337          x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
8338          y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
8339        };
8340      },
8341      draw: function() {
8342  
8343        var ctx = this._chart.ctx,
8344          vm = this._view,
8345          sA = vm.startAngle,
8346          eA = vm.endAngle;
8347  
8348        ctx.beginPath();
8349  
8350        ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
8351        ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
8352  
8353        ctx.closePath();
8354        ctx.strokeStyle = vm.borderColor;
8355        ctx.lineWidth = vm.borderWidth;
8356  
8357        ctx.fillStyle = vm.backgroundColor;
8358  
8359        ctx.fill();
8360        ctx.lineJoin = 'bevel';
8361  
8362        if (vm.borderWidth) {
8363          ctx.stroke();
8364        }
8365      }
8366    });
8367  };
8368  
8369  },{}],35:[function(require,module,exports){
8370  "use strict";
8371  
8372  module.exports = function(Chart) {
8373  
8374      var helpers = Chart.helpers;
8375      var globalDefaults = Chart.defaults.global;
8376  
8377      Chart.defaults.global.elements.line = {
8378          tension: 0.4,
8379          backgroundColor: globalDefaults.defaultColor,
8380          borderWidth: 3,
8381          borderColor: globalDefaults.defaultColor,
8382          borderCapStyle: 'butt',
8383          borderDash: [],
8384          borderDashOffset: 0.0,
8385          borderJoinStyle: 'miter',
8386          fill: true // do we fill in the area between the line and its base axis
8387      };
8388  
8389      Chart.elements.Line = Chart.Element.extend({
8390          lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) {
8391              var me = this;
8392              var ctx = me._chart.ctx;
8393              var spanGaps = me._view ? me._view.spanGaps : false;
8394  
8395              if (point._view.skip && !spanGaps) {
8396                  skipHandler.call(me, previousPoint, point, nextPoint);
8397              } else if (previousPoint._view.skip && !spanGaps) {
8398                  previousSkipHandler.call(me, previousPoint, point, nextPoint);
8399              } else if (point._view.tension === 0) {
8400                  ctx.lineTo(point._view.x, point._view.y);
8401              } else {
8402                  // Line between points

8403                  ctx.bezierCurveTo(
8404                      previousPoint._view.controlPointNextX,
8405                      previousPoint._view.controlPointNextY,
8406                      point._view.controlPointPreviousX,
8407                      point._view.controlPointPreviousY,
8408                      point._view.x,
8409                      point._view.y
8410                  );
8411              }
8412          },
8413  
8414          draw: function() {
8415              var me = this;
8416  
8417              var vm = me._view;
8418              var ctx = me._chart.ctx;
8419              var first = me._children[0];
8420              var last = me._children[me._children.length - 1];
8421  
8422  			function loopBackToStart(drawLineToCenter) {
8423                  if (!first._view.skip && !last._view.skip) {
8424                      // Draw a bezier line from last to first

8425                      ctx.bezierCurveTo(
8426                          last._view.controlPointNextX,
8427                          last._view.controlPointNextY,
8428                          first._view.controlPointPreviousX,
8429                          first._view.controlPointPreviousY,
8430                          first._view.x,
8431                          first._view.y
8432                      );
8433                  } else if (drawLineToCenter) {
8434                      // Go to center

8435                      ctx.lineTo(me._view.scaleZero.x, me._view.scaleZero.y);
8436                  }
8437              }
8438  
8439              ctx.save();
8440  
8441              // If we had points and want to fill this line, do so.

8442              if (me._children.length > 0 && vm.fill) {
8443                  // Draw the background first (so the border is always on top)

8444                  ctx.beginPath();
8445  
8446                  helpers.each(me._children, function(point, index) {
8447                      var previous = helpers.previousItem(me._children, index);
8448                      var next = helpers.nextItem(me._children, index);
8449  
8450                      // First point moves to it's starting position no matter what

8451                      if (index === 0) {
8452                          if (me._loop) {
8453                              ctx.moveTo(vm.scaleZero.x, vm.scaleZero.y);
8454                          } else {
8455                              ctx.moveTo(point._view.x, vm.scaleZero);
8456                          }
8457  
8458                          if (point._view.skip) {
8459                              if (!me._loop) {
8460                                  ctx.moveTo(next._view.x, me._view.scaleZero);
8461                              }
8462                          } else {
8463                              ctx.lineTo(point._view.x, point._view.y);
8464                          }
8465                      } else {
8466                          me.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
8467                              if (me._loop) {
8468                                  // Go to center

8469                                  ctx.lineTo(me._view.scaleZero.x, me._view.scaleZero.y);
8470                              } else {
8471                                  ctx.lineTo(previousPoint._view.x, me._view.scaleZero);
8472                                  ctx.moveTo(nextPoint._view.x, me._view.scaleZero);
8473                              }
8474                          }, function(previousPoint, point) {
8475                              // If we skipped the last point, draw a line to ourselves so that the fill is nice

8476                              ctx.lineTo(point._view.x, point._view.y);
8477                          });
8478                      }
8479                  }, me);
8480  
8481                  // For radial scales, loop back around to the first point

8482                  if (me._loop) {
8483                      loopBackToStart(true);
8484                  } else {
8485                      //Round off the line by going to the base of the chart, back to the start, then fill.

8486                      ctx.lineTo(me._children[me._children.length - 1]._view.x, vm.scaleZero);
8487                      ctx.lineTo(me._children[0]._view.x, vm.scaleZero);
8488                  }
8489  
8490                  ctx.fillStyle = vm.backgroundColor || globalDefaults.defaultColor;
8491                  ctx.closePath();
8492                  ctx.fill();
8493              }
8494  
8495              var globalOptionLineElements = globalDefaults.elements.line;
8496              // Now draw the line between all the points with any borders

8497              ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
8498  
8499              // IE 9 and 10 do not support line dash

8500              if (ctx.setLineDash) {
8501                  ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
8502              }
8503  
8504              ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
8505              ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
8506              ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
8507              ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
8508              ctx.beginPath();
8509  
8510              helpers.each(me._children, function(point, index) {
8511                  var previous = helpers.previousItem(me._children, index);
8512                  var next = helpers.nextItem(me._children, index);
8513  
8514                  if (index === 0) {
8515                      ctx.moveTo(point._view.x, point._view.y);
8516                  } else {
8517                      me.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
8518                          ctx.moveTo(nextPoint._view.x, nextPoint._view.y);
8519                      }, function(previousPoint, point) {
8520                          // If we skipped the last point, move up to our point preventing a line from being drawn

8521                          ctx.moveTo(point._view.x, point._view.y);
8522                      });
8523                  }
8524              }, me);
8525  
8526              if (me._loop && me._children.length > 0) {
8527                  loopBackToStart();
8528              }
8529  
8530              ctx.stroke();
8531              ctx.restore();
8532          }
8533      });
8534  };
8535  },{}],36:[function(require,module,exports){
8536  "use strict";
8537  
8538  module.exports = function(Chart) {
8539  
8540      var helpers = Chart.helpers,
8541          globalOpts = Chart.defaults.global,
8542          defaultColor = globalOpts.defaultColor;
8543  
8544      globalOpts.elements.point = {
8545          radius: 3,
8546          pointStyle: 'circle',
8547          backgroundColor: defaultColor,
8548          borderWidth: 1,
8549          borderColor: defaultColor,
8550          // Hover

8551          hitRadius: 1,
8552          hoverRadius: 4,
8553          hoverBorderWidth: 1
8554      };
8555  
8556      Chart.elements.Point = Chart.Element.extend({
8557          inRange: function(mouseX, mouseY) {
8558              var vm = this._view;
8559              return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
8560          },
8561          inLabelRange: function(mouseX) {
8562              var vm = this._view;
8563              return vm ? (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
8564          },
8565          tooltipPosition: function() {
8566              var vm = this._view;
8567              return {
8568                  x: vm.x,
8569                  y: vm.y,
8570                  padding: vm.radius + vm.borderWidth
8571              };
8572          },
8573          draw: function() {
8574              var vm = this._view;
8575              var ctx = this._chart.ctx;
8576              var pointStyle = vm.pointStyle;
8577              var radius = vm.radius;
8578              var x = vm.x;
8579              var y = vm.y;
8580              var type, edgeLength, xOffset, yOffset, height, size;
8581  
8582              if (vm.skip) {
8583                  return;
8584              }
8585  
8586              if (typeof pointStyle === 'object') {
8587                  type = pointStyle.toString();
8588                  if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
8589                      ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2);
8590                      return;
8591                  }
8592              }
8593  
8594              if (isNaN(radius) || radius <= 0) {
8595                  return;
8596              }
8597  
8598              ctx.strokeStyle = vm.borderColor || defaultColor;
8599              ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth);
8600              ctx.fillStyle = vm.backgroundColor || defaultColor;
8601  
8602              switch (pointStyle) {
8603              // Default includes circle

8604              default:
8605                  ctx.beginPath();
8606                  ctx.arc(x, y, radius, 0, Math.PI * 2);
8607                  ctx.closePath();
8608                  ctx.fill();
8609                  break;
8610              case 'triangle':
8611                  ctx.beginPath();
8612                  edgeLength = 3 * radius / Math.sqrt(3);
8613                  height = edgeLength * Math.sqrt(3) / 2;
8614                  ctx.moveTo(x - edgeLength / 2, y + height / 3);
8615                  ctx.lineTo(x + edgeLength / 2, y + height / 3);
8616                  ctx.lineTo(x, y - 2 * height / 3);
8617                  ctx.closePath();
8618                  ctx.fill();
8619                  break;
8620              case 'rect':
8621                  size = 1 / Math.SQRT2 * radius;
8622                  ctx.fillRect(x - size, y - size, 2 * size,  2 * size);
8623                  ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
8624                  break;
8625              case 'rectRot':
8626                  size = 1 / Math.SQRT2 * radius;
8627                  ctx.beginPath();
8628                  ctx.moveTo(x - size, y);
8629                  ctx.lineTo(x, y + size);
8630                  ctx.lineTo(x + size, y);
8631                  ctx.lineTo(x, y - size);
8632                  ctx.closePath();
8633                  ctx.fill();
8634                  break;
8635              case 'cross':
8636                  ctx.beginPath();
8637                  ctx.moveTo(x, y + radius);
8638                  ctx.lineTo(x, y - radius);
8639                  ctx.moveTo(x - radius, y);
8640                  ctx.lineTo(x + radius, y);
8641                  ctx.closePath();
8642                  break;
8643              case 'crossRot':
8644                  ctx.beginPath();
8645                  xOffset = Math.cos(Math.PI / 4) * radius;
8646                  yOffset = Math.sin(Math.PI / 4) * radius;
8647                  ctx.moveTo(x - xOffset, y - yOffset);
8648                  ctx.lineTo(x + xOffset, y + yOffset);
8649                  ctx.moveTo(x - xOffset, y + yOffset);
8650                  ctx.lineTo(x + xOffset, y - yOffset);
8651                  ctx.closePath();
8652                  break;
8653              case 'star':
8654                  ctx.beginPath();
8655                  ctx.moveTo(x, y + radius);
8656                  ctx.lineTo(x, y - radius);
8657                  ctx.moveTo(x - radius, y);
8658                  ctx.lineTo(x + radius, y);
8659                  xOffset = Math.cos(Math.PI / 4) * radius;
8660                  yOffset = Math.sin(Math.PI / 4) * radius;
8661                  ctx.moveTo(x - xOffset, y - yOffset);
8662                  ctx.lineTo(x + xOffset, y + yOffset);
8663                  ctx.moveTo(x - xOffset, y + yOffset);
8664                  ctx.lineTo(x + xOffset, y - yOffset);
8665                  ctx.closePath();
8666                  break;
8667              case 'line':
8668                  ctx.beginPath();
8669                  ctx.moveTo(x - radius, y);
8670                  ctx.lineTo(x + radius, y);
8671                  ctx.closePath();
8672                  break;
8673              case 'dash':
8674                  ctx.beginPath();
8675                  ctx.moveTo(x, y);
8676                  ctx.lineTo(x + radius, y);
8677                  ctx.closePath();
8678                  break;
8679              }
8680  
8681              ctx.stroke();
8682          }
8683      });
8684  };
8685  
8686  },{}],37:[function(require,module,exports){
8687  "use strict";
8688  
8689  module.exports = function(Chart) {
8690  
8691      var helpers = Chart.helpers,
8692          globalOpts = Chart.defaults.global;
8693  
8694      globalOpts.elements.rectangle = {
8695          backgroundColor: globalOpts.defaultColor,
8696          borderWidth: 0,
8697          borderColor: globalOpts.defaultColor,
8698          borderSkipped: 'bottom'
8699      };
8700  
8701      Chart.elements.Rectangle = Chart.Element.extend({
8702          draw: function() {
8703              var ctx = this._chart.ctx;
8704              var vm = this._view;
8705  
8706              var halfWidth = vm.width / 2,
8707                  leftX = vm.x - halfWidth,
8708                  rightX = vm.x + halfWidth,
8709                  top = vm.base - (vm.base - vm.y),
8710                  halfStroke = vm.borderWidth / 2;
8711  
8712              // Canvas doesn't allow us to stroke inside the width so we can

8713              // adjust the sizes to fit if we're setting a stroke on the line

8714              if (vm.borderWidth) {
8715                  leftX += halfStroke;
8716                  rightX -= halfStroke;
8717                  top += halfStroke;
8718              }
8719  
8720              ctx.beginPath();
8721              ctx.fillStyle = vm.backgroundColor;
8722              ctx.strokeStyle = vm.borderColor;
8723              ctx.lineWidth = vm.borderWidth;
8724  
8725              // Corner points, from bottom-left to bottom-right clockwise

8726              // | 1 2 |

8727              // | 0 3 |

8728              var corners = [
8729                  [leftX, vm.base],
8730                  [leftX, top],
8731                  [rightX, top],
8732                  [rightX, vm.base]
8733              ];
8734  
8735              // Find first (starting) corner with fallback to 'bottom' 

8736              var borders = ['bottom', 'left', 'top', 'right'];
8737              var startCorner = borders.indexOf(vm.borderSkipped, 0);
8738              if (startCorner === -1)
8739                  startCorner = 0;
8740  
8741  			function cornerAt(index) {
8742                  return corners[(startCorner + index) % 4];
8743              }
8744  
8745              // Draw rectangle from 'startCorner'

8746              ctx.moveTo.apply(ctx, cornerAt(0));
8747              for (var i = 1; i < 4; i++)
8748                  ctx.lineTo.apply(ctx, cornerAt(i));
8749  
8750              ctx.fill();
8751              if (vm.borderWidth) {
8752                  ctx.stroke();
8753              }
8754          },
8755          height: function() {
8756              var vm = this._view;
8757              return vm.base - vm.y;
8758          },
8759          inRange: function(mouseX, mouseY) {
8760              var vm = this._view;
8761              return vm ? 
8762                      (vm.y < vm.base ? 
8763                          (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.y && mouseY <= vm.base) :
8764                          (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.base && mouseY <= vm.y)) :
8765                      false;
8766          },
8767          inLabelRange: function(mouseX) {
8768              var vm = this._view;
8769              return vm ? (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) : false;
8770          },
8771          tooltipPosition: function() {
8772              var vm = this._view;
8773              return {
8774                  x: vm.x,
8775                  y: vm.y
8776              };
8777          }
8778      });
8779  
8780  };
8781  },{}],38:[function(require,module,exports){
8782  "use strict";
8783  
8784  module.exports = function(Chart) {
8785  
8786      var helpers = Chart.helpers;
8787      // Default config for a category scale

8788      var defaultConfig = {
8789          position: "bottom"
8790      };
8791  
8792      var DatasetScale = Chart.Scale.extend({
8793          // Implement this so that 

8794          determineDataLimits: function() {
8795              var me = this;
8796              me.minIndex = 0;
8797              me.maxIndex = me.chart.data.labels.length - 1;
8798              var findIndex;
8799  
8800              if (me.options.ticks.min !== undefined) {
8801                  // user specified min value

8802                  findIndex = helpers.indexOf(me.chart.data.labels, me.options.ticks.min);
8803                  me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
8804              }
8805  
8806              if (me.options.ticks.max !== undefined) {
8807                  // user specified max value

8808                  findIndex = helpers.indexOf(me.chart.data.labels, me.options.ticks.max);
8809                  me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
8810              }
8811  
8812              me.min = me.chart.data.labels[me.minIndex];
8813              me.max = me.chart.data.labels[me.maxIndex];
8814          },
8815  
8816          buildTicks: function(index) {
8817              var me = this;
8818              // If we are viewing some subset of labels, slice the original array

8819              me.ticks = (me.minIndex === 0 && me.maxIndex === me.chart.data.labels.length - 1) ? me.chart.data.labels : me.chart.data.labels.slice(me.minIndex, me.maxIndex + 1);
8820          },
8821  
8822          getLabelForIndex: function(index, datasetIndex) {
8823              return this.ticks[index];
8824          },
8825  
8826          // Used to get data value locations.  Value can either be an index or a numerical value

8827          getPixelForValue: function(value, index, datasetIndex, includeOffset) {
8828              var me = this;
8829              // 1 is added because we need the length but we have the indexes

8830              var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
8831  
8832              if (me.isHorizontal()) {
8833                  var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
8834                  var valueWidth = innerWidth / offsetAmt;
8835                  var widthOffset = (valueWidth * (index - me.minIndex)) + me.paddingLeft;
8836  
8837                  if (me.options.gridLines.offsetGridLines && includeOffset) {
8838                      widthOffset += (valueWidth / 2);
8839                  }
8840  
8841                  return me.left + Math.round(widthOffset);
8842              } else {
8843                  var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
8844                  var valueHeight = innerHeight / offsetAmt;
8845                  var heightOffset = (valueHeight * (index - me.minIndex)) + me.paddingTop;
8846  
8847                  if (me.options.gridLines.offsetGridLines && includeOffset) {
8848                      heightOffset += (valueHeight / 2);
8849                  }
8850  
8851                  return me.top + Math.round(heightOffset);
8852              }
8853          },
8854          getPixelForTick: function(index, includeOffset) {
8855              return this.getPixelForValue(this.ticks[index], index + this.minIndex, null, includeOffset);
8856          },
8857          getValueForPixel: function(pixel) {
8858              var me = this;
8859              var value;
8860              var offsetAmt = Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
8861              var horz = me.isHorizontal();
8862              var innerDimension = horz ? me.width - (me.paddingLeft + me.paddingRight) : me.height - (me.paddingTop + me.paddingBottom);
8863              var valueDimension = innerDimension / offsetAmt;
8864  
8865              if (me.options.gridLines.offsetGridLines) {
8866                  pixel -= (valueDimension / 2);
8867              }
8868              pixel -= horz ? me.paddingLeft : me.paddingTop;
8869  
8870              if (pixel <= 0) {
8871                  value = 0;
8872              } else {
8873                  value = Math.round(pixel / valueDimension);
8874              }
8875  
8876              return value;
8877          }
8878      });
8879  
8880      Chart.scaleService.registerScaleType("category", DatasetScale, defaultConfig);
8881  
8882  };
8883  },{}],39:[function(require,module,exports){
8884  "use strict";
8885  
8886  module.exports = function(Chart) {
8887  
8888      var helpers = Chart.helpers;
8889  
8890      var defaultConfig = {
8891          position: "left",
8892          ticks: {
8893              callback: function(tickValue, index, ticks) {
8894                  // If we have lots of ticks, don't use the ones

8895                  var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
8896  
8897                  // If we have a number like 2.5 as the delta, figure out how many decimal places we need

8898                  if (Math.abs(delta) > 1) {
8899                      if (tickValue !== Math.floor(tickValue)) {
8900                          // not an integer

8901                          delta = tickValue - Math.floor(tickValue);
8902                      }
8903                  }
8904  
8905                  var logDelta = helpers.log10(Math.abs(delta));
8906                  var tickString = '';
8907  
8908                  if (tickValue !== 0) {
8909                      var numDecimal = -1 * Math.floor(logDelta);
8910                      numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places

8911                      tickString = tickValue.toFixed(numDecimal);
8912                  } else {
8913                      tickString = '0'; // never show decimal places for 0

8914                  }
8915  
8916                  return tickString;
8917              }
8918          }
8919      };
8920  
8921      var LinearScale = Chart.LinearScaleBase.extend({
8922          determineDataLimits: function() {
8923              var me = this;
8924              var opts = me.options;
8925              var tickOpts = opts.ticks;
8926              var chart = me.chart;
8927              var data = chart.data;
8928              var datasets = data.datasets;
8929              var isHorizontal = me.isHorizontal();
8930  
8931  			function IDMatches(meta) {
8932                  return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
8933              }
8934  
8935              // First Calculate the range

8936              me.min = null;
8937              me.max = null;
8938  
8939              if (opts.stacked) {
8940                  var valuesPerType = {};
8941                  var hasPositiveValues = false;
8942                  var hasNegativeValues = false;
8943  
8944                  helpers.each(datasets, function(dataset, datasetIndex) {
8945                      var meta = chart.getDatasetMeta(datasetIndex);
8946                      if (valuesPerType[meta.type] === undefined) {
8947                          valuesPerType[meta.type] = {
8948                              positiveValues: [],
8949                              negativeValues: []
8950                          };
8951                      }
8952  
8953                      // Store these per type

8954                      var positiveValues = valuesPerType[meta.type].positiveValues;
8955                      var negativeValues = valuesPerType[meta.type].negativeValues;
8956  
8957                      if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
8958                          helpers.each(dataset.data, function(rawValue, index) {
8959                              var value = +me.getRightValue(rawValue);
8960                              if (isNaN(value) || meta.data[index].hidden) {
8961                                  return;
8962                              }
8963  
8964                              positiveValues[index] = positiveValues[index] || 0;
8965                              negativeValues[index] = negativeValues[index] || 0;
8966  
8967                              if (opts.relativePoints) {
8968                                  positiveValues[index] = 100;
8969                              } else {
8970                                  if (value < 0) {
8971                                      hasNegativeValues = true;
8972                                      negativeValues[index] += value;
8973                                  } else {
8974                                      hasPositiveValues = true;
8975                                      positiveValues[index] += value;
8976                                  }
8977                              }
8978                          });
8979                      }
8980                  });
8981  
8982                  helpers.each(valuesPerType, function(valuesForType) {
8983                      var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
8984                      var minVal = helpers.min(values);
8985                      var maxVal = helpers.max(values);
8986                      me.min = me.min === null ? minVal : Math.min(me.min, minVal);
8987                      me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
8988                  });
8989  
8990              } else {
8991                  helpers.each(datasets, function(dataset, datasetIndex) {
8992                      var meta = chart.getDatasetMeta(datasetIndex);
8993                      if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
8994                          helpers.each(dataset.data, function(rawValue, index) {
8995                              var value = +me.getRightValue(rawValue);
8996                              if (isNaN(value) || meta.data[index].hidden) {
8997                                  return;
8998                              }
8999  
9000                              if (me.min === null) {
9001                                  me.min = value;
9002                              } else if (value < me.min) {
9003                                  me.min = value;
9004                              }
9005  
9006                              if (me.max === null) {
9007                                  me.max = value;
9008                              } else if (value > me.max) {
9009                                  me.max = value;
9010                              }
9011                          });
9012                      }
9013                  });
9014              }
9015  
9016              // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero

9017              this.handleTickRangeOptions();
9018          },
9019          getTickLimit: function() {
9020              var maxTicks;
9021              var me = this;
9022              var tickOpts = me.options.ticks;
9023  
9024              if (me.isHorizontal()) {
9025                  maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
9026              } else {
9027                  // The factor of 2 used to scale the font size has been experimentally determined.

9028                  var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize);
9029                  maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
9030              }
9031  
9032              return maxTicks;
9033          },
9034          // Called after the ticks are built. We need 

9035          handleDirectionalChanges: function() {
9036              if (!this.isHorizontal()) {
9037                  // We are in a vertical orientation. The top value is the highest. So reverse the array

9038                  this.ticks.reverse();
9039              }
9040          },
9041          getLabelForIndex: function(index, datasetIndex) {
9042              return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
9043          },
9044          // Utils

9045          getPixelForValue: function(value, index, datasetIndex, includeOffset) {
9046              // This must be called after fit has been run so that

9047              //      this.left, this.top, this.right, and this.bottom have been defined

9048              var me = this;
9049              var paddingLeft = me.paddingLeft;
9050              var paddingBottom = me.paddingBottom;
9051              var start = me.start;
9052  
9053              var rightValue = +me.getRightValue(value);
9054              var pixel;
9055              var innerDimension;
9056              var range = me.end - start;
9057  
9058              if (me.isHorizontal()) {
9059                  innerDimension = me.width - (paddingLeft + me.paddingRight);
9060                  pixel = me.left + (innerDimension / range * (rightValue - start));
9061                  return Math.round(pixel + paddingLeft);
9062              } else {
9063                  innerDimension = me.height - (me.paddingTop + paddingBottom);
9064                  pixel = (me.bottom - paddingBottom) - (innerDimension / range * (rightValue - start));
9065                  return Math.round(pixel);
9066              }
9067          },
9068          getValueForPixel: function(pixel) {
9069              var me = this;
9070              var isHorizontal = me.isHorizontal();
9071              var paddingLeft = me.paddingLeft;
9072              var paddingBottom = me.paddingBottom;
9073              var innerDimension = isHorizontal ? me.width - (paddingLeft + me.paddingRight) : me.height - (me.paddingTop + paddingBottom);
9074              var offset = (isHorizontal ? pixel - me.left - paddingLeft : me.bottom - paddingBottom - pixel) / innerDimension;
9075              return me.start + ((me.end - me.start) * offset);
9076          },
9077          getPixelForTick: function(index, includeOffset) {
9078              return this.getPixelForValue(this.ticksAsNumbers[index], null, null, includeOffset);
9079          }
9080      });
9081      Chart.scaleService.registerScaleType("linear", LinearScale, defaultConfig);
9082  
9083  };
9084  },{}],40:[function(require,module,exports){
9085  "use strict";
9086  
9087  module.exports = function(Chart) {
9088  
9089      var helpers = Chart.helpers,
9090          noop = helpers.noop;
9091  
9092      Chart.LinearScaleBase = Chart.Scale.extend({
9093          handleTickRangeOptions: function() {
9094              var me = this;
9095              var opts = me.options;
9096              var tickOpts = opts.ticks;
9097  
9098              // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,

9099              // do nothing since that would make the chart weird. If the user really wants a weird chart

9100              // axis, they can manually override it

9101              if (tickOpts.beginAtZero) {
9102                  var minSign = helpers.sign(me.min);
9103                  var maxSign = helpers.sign(me.max);
9104  
9105                  if (minSign < 0 && maxSign < 0) {
9106                      // move the top up to 0

9107                      me.max = 0;
9108                  } else if (minSign > 0 && maxSign > 0) {
9109                      // move the botttom down to 0

9110                      me.min = 0;
9111                  }
9112              }
9113  
9114              if (tickOpts.min !== undefined) {
9115                  me.min = tickOpts.min;
9116              } else if (tickOpts.suggestedMin !== undefined) {
9117                  me.min = Math.min(me.min, tickOpts.suggestedMin);
9118              }
9119  
9120              if (tickOpts.max !== undefined) {
9121                  me.max = tickOpts.max;
9122              } else if (tickOpts.suggestedMax !== undefined) {
9123                  me.max = Math.max(me.max, tickOpts.suggestedMax);
9124              }
9125  
9126              if (me.min === me.max) {
9127                  me.max++;
9128  
9129                  if (!tickOpts.beginAtZero) {
9130                      me.min--;
9131                  }
9132              }
9133          },
9134          getTickLimit: noop,
9135          handleDirectionalChanges: noop,
9136  
9137          buildTicks: function() {
9138              var me = this;
9139              var opts = me.options;
9140              var tickOpts = opts.ticks;
9141              var getValueOrDefault = helpers.getValueOrDefault;
9142              var isHorizontal = me.isHorizontal();
9143  
9144              var ticks = me.ticks = [];
9145  
9146              // Figure out what the max number of ticks we can support it is based on the size of

9147              // the axis area. For now, we say that the minimum tick spacing in pixels must be 50

9148              // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on

9149              // the graph

9150  
9151              var maxTicks = me.getTickLimit();
9152  
9153              // Make sure we always have at least 2 ticks

9154              maxTicks = Math.max(2, maxTicks);
9155  
9156              // To get a "nice" value for the tick spacing, we will use the appropriately named

9157              // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks

9158              // for details.

9159  
9160              var spacing;
9161              var fixedStepSizeSet = (tickOpts.fixedStepSize && tickOpts.fixedStepSize > 0) || (tickOpts.stepSize && tickOpts.stepSize > 0);
9162              if (fixedStepSizeSet) {
9163                  spacing = getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize);
9164              } else {
9165                  var niceRange = helpers.niceNum(me.max - me.min, false);
9166                  spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
9167              }
9168              var niceMin = Math.floor(me.min / spacing) * spacing;
9169              var niceMax = Math.ceil(me.max / spacing) * spacing;
9170              var numSpaces = (niceMax - niceMin) / spacing;
9171  
9172              // If very close to our rounded value, use it.

9173              if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
9174                  numSpaces = Math.round(numSpaces);
9175              } else {
9176                  numSpaces = Math.ceil(numSpaces);
9177              }
9178  
9179              // Put the values into the ticks array

9180              ticks.push(tickOpts.min !== undefined ? tickOpts.min : niceMin);
9181              for (var j = 1; j < numSpaces; ++j) {
9182                  ticks.push(niceMin + (j * spacing));
9183              }
9184              ticks.push(tickOpts.max !== undefined ? tickOpts.max : niceMax);
9185  
9186              me.handleDirectionalChanges();
9187  
9188              // At this point, we need to update our max and min given the tick values since we have expanded the

9189              // range of the scale

9190              me.max = helpers.max(ticks);
9191              me.min = helpers.min(ticks);
9192  
9193              if (tickOpts.reverse) {
9194                  ticks.reverse();
9195  
9196                  me.start = me.max;
9197                  me.end = me.min;
9198              } else {
9199                  me.start = me.min;
9200                  me.end = me.max;
9201              }
9202          },
9203          convertTicksToLabels: function() {
9204              var me = this;
9205              me.ticksAsNumbers = me.ticks.slice();
9206              me.zeroLineIndex = me.ticks.indexOf(0);
9207  
9208              Chart.Scale.prototype.convertTicksToLabels.call(me);
9209          },
9210      });
9211  };
9212  },{}],41:[function(require,module,exports){
9213  "use strict";
9214  
9215  module.exports = function(Chart) {
9216  
9217      var helpers = Chart.helpers;
9218  
9219      var defaultConfig = {
9220          position: "left",
9221  
9222          // label settings

9223          ticks: {
9224              callback: function(value, index, arr) {
9225                  var remain = value / (Math.pow(10, Math.floor(helpers.log10(value))));
9226  
9227                  if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === arr.length - 1) {
9228                      return value.toExponential();
9229                  } else {
9230                      return '';
9231                  }
9232              }
9233          }
9234      };
9235  
9236      var LogarithmicScale = Chart.Scale.extend({
9237          determineDataLimits: function() {
9238              var me = this;
9239              var opts = me.options;
9240              var tickOpts = opts.ticks;
9241              var chart = me.chart;
9242              var data = chart.data;
9243              var datasets = data.datasets;
9244              var getValueOrDefault = helpers.getValueOrDefault;
9245              var isHorizontal = me.isHorizontal();
9246  			function IDMatches(meta) {
9247                  return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
9248              }
9249  
9250              // Calculate Range

9251              me.min = null;
9252              me.max = null;
9253  
9254              if (opts.stacked) {
9255                  var valuesPerType = {};
9256  
9257                  helpers.each(datasets, function(dataset, datasetIndex) {
9258                      var meta = chart.getDatasetMeta(datasetIndex);
9259                      if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
9260                          if (valuesPerType[meta.type] === undefined) {
9261                              valuesPerType[meta.type] = [];
9262                          }
9263  
9264                          helpers.each(dataset.data, function(rawValue, index) {
9265                              var values = valuesPerType[meta.type];
9266                              var value = +me.getRightValue(rawValue);
9267                              if (isNaN(value) || meta.data[index].hidden) {
9268                                  return;
9269                              }
9270  
9271                              values[index] = values[index] || 0;
9272  
9273                              if (opts.relativePoints) {
9274                                  values[index] = 100;
9275                              } else {
9276                                  // Don't need to split positive and negative since the log scale can't handle a 0 crossing

9277                                  values[index] += value;
9278                              }
9279                          });
9280                      }
9281                  });
9282  
9283                  helpers.each(valuesPerType, function(valuesForType) {
9284                      var minVal = helpers.min(valuesForType);
9285                      var maxVal = helpers.max(valuesForType);
9286                      me.min = me.min === null ? minVal : Math.min(me.min, minVal);
9287                      me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
9288                  });
9289  
9290              } else {
9291                  helpers.each(datasets, function(dataset, datasetIndex) {
9292                      var meta = chart.getDatasetMeta(datasetIndex);
9293                      if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
9294                          helpers.each(dataset.data, function(rawValue, index) {
9295                              var value = +me.getRightValue(rawValue);
9296                              if (isNaN(value) || meta.data[index].hidden) {
9297                                  return;
9298                              }
9299  
9300                              if (me.min === null) {
9301                                  me.min = value;
9302                              } else if (value < me.min) {
9303                                  me.min = value;
9304                              }
9305  
9306                              if (me.max === null) {
9307                                  me.max = value;
9308                              } else if (value > me.max) {
9309                                  me.max = value;
9310                              }
9311                          });
9312                      }
9313                  });
9314              }
9315  
9316              me.min = getValueOrDefault(tickOpts.min, me.min);
9317              me.max = getValueOrDefault(tickOpts.max, me.max);
9318  
9319              if (me.min === me.max) {
9320                  if (me.min !== 0 && me.min !== null) {
9321                      me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
9322                      me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
9323                  } else {
9324                      me.min = 1;
9325                      me.max = 10;
9326                  }
9327              }
9328          },
9329          buildTicks: function() {
9330              var me = this;
9331              var opts = me.options;
9332              var tickOpts = opts.ticks;
9333              var getValueOrDefault = helpers.getValueOrDefault;
9334  
9335              // Reset the ticks array. Later on, we will draw a grid line at these positions

9336              // The array simply contains the numerical value of the spots where ticks will be

9337              var ticks = me.ticks = [];
9338  
9339              // Figure out what the max number of ticks we can support it is based on the size of

9340              // the axis area. For now, we say that the minimum tick spacing in pixels must be 50

9341              // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on

9342              // the graph

9343  
9344              var tickVal = getValueOrDefault(tickOpts.min, Math.pow(10, Math.floor(helpers.log10(me.min))));
9345  
9346              while (tickVal < me.max) {
9347                  ticks.push(tickVal);
9348  
9349                  var exp = Math.floor(helpers.log10(tickVal));
9350                  var significand = Math.floor(tickVal / Math.pow(10, exp)) + 1;
9351  
9352                  if (significand === 10) {
9353                      significand = 1;
9354                      ++exp;
9355                  }
9356  
9357                  tickVal = significand * Math.pow(10, exp);
9358              }
9359  
9360              var lastTick = getValueOrDefault(tickOpts.max, tickVal);
9361              ticks.push(lastTick);
9362  
9363              if (!me.isHorizontal()) {
9364                  // We are in a vertical orientation. The top value is the highest. So reverse the array

9365                  ticks.reverse();
9366              }
9367  
9368              // At this point, we need to update our max and min given the tick values since we have expanded the

9369              // range of the scale

9370              me.max = helpers.max(ticks);
9371              me.min = helpers.min(ticks);
9372  
9373              if (tickOpts.reverse) {
9374                  ticks.reverse();
9375  
9376                  me.start = me.max;
9377                  me.end = me.min;
9378              } else {
9379                  me.start = me.min;
9380                  me.end = me.max;
9381              }
9382          },
9383          convertTicksToLabels: function() {
9384              this.tickValues = this.ticks.slice();
9385  
9386              Chart.Scale.prototype.convertTicksToLabels.call(this);
9387          },
9388          // Get the correct tooltip label

9389          getLabelForIndex: function(index, datasetIndex) {
9390              return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
9391          },
9392          getPixelForTick: function(index, includeOffset) {
9393              return this.getPixelForValue(this.tickValues[index], null, null, includeOffset);
9394          },
9395          getPixelForValue: function(value, index, datasetIndex, includeOffset) {
9396              var me = this;
9397              var innerDimension;
9398              var pixel;
9399  
9400              var start = me.start;
9401              var newVal = +me.getRightValue(value);
9402              var range = helpers.log10(me.end) - helpers.log10(start);
9403              var paddingTop = me.paddingTop;
9404              var paddingBottom = me.paddingBottom;
9405              var paddingLeft = me.paddingLeft;
9406  
9407              if (me.isHorizontal()) {
9408  
9409                  if (newVal === 0) {
9410                      pixel = me.left + paddingLeft;
9411                  } else {
9412                      innerDimension = me.width - (paddingLeft + me.paddingRight);
9413                      pixel = me.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
9414                      pixel += paddingLeft;
9415                  }
9416              } else {
9417                  // Bottom - top since pixels increase downard on a screen

9418                  if (newVal === 0) {
9419                      pixel = me.top + paddingTop;
9420                  } else {
9421                      innerDimension = me.height - (paddingTop + paddingBottom);
9422                      pixel = (me.bottom - paddingBottom) - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
9423                  }
9424              }
9425  
9426              return pixel;
9427          },
9428          getValueForPixel: function(pixel) {
9429              var me = this;
9430              var offset;
9431              var range = helpers.log10(me.end) - helpers.log10(me.start);
9432              var value;
9433              var innerDimension;
9434  
9435              if (me.isHorizontal()) {
9436                  innerDimension = me.width - (me.paddingLeft + me.paddingRight);
9437                  value = me.start * Math.pow(10, (pixel - me.left - me.paddingLeft) * range / innerDimension);
9438              } else {
9439                  innerDimension = me.height - (me.paddingTop + me.paddingBottom);
9440                  value = Math.pow(10, (me.bottom - me.paddingBottom - pixel) * range / innerDimension) / me.start;
9441              }
9442  
9443              return value;
9444          }
9445      });
9446      Chart.scaleService.registerScaleType("logarithmic", LogarithmicScale, defaultConfig);
9447  
9448  };
9449  },{}],42:[function(require,module,exports){
9450  "use strict";
9451  
9452  module.exports = function(Chart) {
9453  
9454      var helpers = Chart.helpers;
9455      var globalDefaults = Chart.defaults.global;
9456  
9457      var defaultConfig = {
9458          display: true,
9459  
9460          //Boolean - Whether to animate scaling the chart from the centre

9461          animate: true,
9462          lineArc: false,
9463          position: "chartArea",
9464  
9465          angleLines: {
9466              display: true,
9467              color: "rgba(0, 0, 0, 0.1)",
9468              lineWidth: 1
9469          },
9470  
9471          // label settings

9472          ticks: {
9473              //Boolean - Show a backdrop to the scale label

9474              showLabelBackdrop: true,
9475  
9476              //String - The colour of the label backdrop

9477              backdropColor: "rgba(255,255,255,0.75)",
9478  
9479              //Number - The backdrop padding above & below the label in pixels

9480              backdropPaddingY: 2,
9481  
9482              //Number - The backdrop padding to the side of the label in pixels

9483              backdropPaddingX: 2
9484          },
9485  
9486          pointLabels: {
9487              //Number - Point label font size in pixels

9488              fontSize: 10,
9489  
9490              //Function - Used to convert point labels

9491              callback: function(label) {
9492                  return label;
9493              }
9494          }
9495      };
9496  
9497      var LinearRadialScale = Chart.LinearScaleBase.extend({
9498          getValueCount: function() {
9499              return this.chart.data.labels.length;
9500          },
9501          setDimensions: function() {
9502              var me = this;
9503              var opts = me.options;
9504              var tickOpts = opts.ticks;
9505              // Set the unconstrained dimension before label rotation

9506              me.width = me.maxWidth;
9507              me.height = me.maxHeight;
9508              me.xCenter = Math.round(me.width / 2);
9509              me.yCenter = Math.round(me.height / 2);
9510  
9511              var minSize = helpers.min([me.height, me.width]);
9512              var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
9513              me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
9514          },
9515          determineDataLimits: function() {
9516              var me = this;
9517              var chart = me.chart;
9518              me.min = null;
9519              me.max = null;
9520  
9521  
9522              helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
9523                  if (chart.isDatasetVisible(datasetIndex)) {
9524                      var meta = chart.getDatasetMeta(datasetIndex);
9525  
9526                      helpers.each(dataset.data, function(rawValue, index) {
9527                          var value = +me.getRightValue(rawValue);
9528                          if (isNaN(value) || meta.data[index].hidden) {
9529                              return;
9530                          }
9531  
9532                          if (me.min === null) {
9533                              me.min = value;
9534                          } else if (value < me.min) {
9535                              me.min = value;
9536                          }
9537  
9538                          if (me.max === null) {
9539                              me.max = value;
9540                          } else if (value > me.max) {
9541                              me.max = value;
9542                          }
9543                      });
9544                  }
9545              });
9546  
9547              // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero

9548              me.handleTickRangeOptions();
9549          },
9550          getTickLimit: function() {
9551              var tickOpts = this.options.ticks;
9552              var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
9553              return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
9554          },
9555          convertTicksToLabels: function() {
9556              var me = this;
9557              Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);
9558  
9559              // Point labels

9560              me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
9561          },
9562          getLabelForIndex: function(index, datasetIndex) {
9563              return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
9564          },
9565          fit: function() {
9566              /*

9567               * Right, this is really confusing and there is a lot of maths going on here

9568               * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9

9569               *

9570               * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif

9571               *

9572               * Solution:

9573               *

9574               * We assume the radius of the polygon is half the size of the canvas at first

9575               * at each index we check if the text overlaps.

9576               *

9577               * Where it does, we store that angle and that index.

9578               *

9579               * After finding the largest index and angle we calculate how much we need to remove

9580               * from the shape radius to move the point inwards by that x.

9581               *

9582               * We average the left and right distances to get the maximum shape radius that can fit in the box

9583               * along with labels.

9584               *

9585               * Once we have that, we can find the centre point for the chart, by taking the x text protrusion

9586               * on each side, removing that from the size, halving it and adding the left x protrusion width.

9587               *

9588               * This will mean we have a shape fitted to the canvas, as large as it can be with the labels

9589               * and position it in the most space efficient manner

9590               *

9591               * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif

9592               */
9593  
9594              var pointLabels = this.options.pointLabels;
9595              var pointLabelFontSize = helpers.getValueOrDefault(pointLabels.fontSize, globalDefaults.defaultFontSize);
9596              var pointLabeFontStyle = helpers.getValueOrDefault(pointLabels.fontStyle, globalDefaults.defaultFontStyle);
9597              var pointLabeFontFamily = helpers.getValueOrDefault(pointLabels.fontFamily, globalDefaults.defaultFontFamily);
9598              var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
9599  
9600              // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.

9601              // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points

9602              var largestPossibleRadius = helpers.min([(this.height / 2 - pointLabelFontSize - 5), this.width / 2]),
9603                  pointPosition,
9604                  i,
9605                  textWidth,
9606                  halfTextWidth,
9607                  furthestRight = this.width,
9608                  furthestRightIndex,
9609                  furthestRightAngle,
9610                  furthestLeft = 0,
9611                  furthestLeftIndex,
9612                  furthestLeftAngle,
9613                  xProtrusionLeft,
9614                  xProtrusionRight,
9615                  radiusReductionRight,
9616                  radiusReductionLeft,
9617                  maxWidthRadius;
9618              this.ctx.font = pointLabeFont;
9619  
9620              for (i = 0; i < this.getValueCount(); i++) {
9621                  // 5px to space the text slightly out - similar to what we do in the draw function.

9622                  pointPosition = this.getPointPosition(i, largestPossibleRadius);
9623                  textWidth = this.ctx.measureText(this.pointLabels[i] ? this.pointLabels[i] : '').width + 5;
9624                  if (i === 0 || i === this.getValueCount() / 2) {
9625                      // If we're at index zero, or exactly the middle, we're at exactly the top/bottom

9626                      // of the radar chart, so text will be aligned centrally, so we'll half it and compare

9627                      // w/left and right text sizes

9628                      halfTextWidth = textWidth / 2;
9629                      if (pointPosition.x + halfTextWidth > furthestRight) {
9630                          furthestRight = pointPosition.x + halfTextWidth;
9631                          furthestRightIndex = i;
9632                      }
9633                      if (pointPosition.x - halfTextWidth < furthestLeft) {
9634                          furthestLeft = pointPosition.x - halfTextWidth;
9635                          furthestLeftIndex = i;
9636                      }
9637                  } else if (i < this.getValueCount() / 2) {
9638                      // Less than half the values means we'll left align the text

9639                      if (pointPosition.x + textWidth > furthestRight) {
9640                          furthestRight = pointPosition.x + textWidth;
9641                          furthestRightIndex = i;
9642                      }
9643                  } else if (i > this.getValueCount() / 2) {
9644                      // More than half the values means we'll right align the text

9645                      if (pointPosition.x - textWidth < furthestLeft) {
9646                          furthestLeft = pointPosition.x - textWidth;
9647                          furthestLeftIndex = i;
9648                      }
9649                  }
9650              }
9651  
9652              xProtrusionLeft = furthestLeft;
9653              xProtrusionRight = Math.ceil(furthestRight - this.width);
9654  
9655              furthestRightAngle = this.getIndexAngle(furthestRightIndex);
9656              furthestLeftAngle = this.getIndexAngle(furthestLeftIndex);
9657  
9658              radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI / 2);
9659              radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI / 2);
9660  
9661              // Ensure we actually need to reduce the size of the chart

9662              radiusReductionRight = (helpers.isNumber(radiusReductionRight)) ? radiusReductionRight : 0;
9663              radiusReductionLeft = (helpers.isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0;
9664  
9665              this.drawingArea = Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2);
9666              this.setCenterPoint(radiusReductionLeft, radiusReductionRight);
9667          },
9668          setCenterPoint: function(leftMovement, rightMovement) {
9669              var me = this;
9670              var maxRight = me.width - rightMovement - me.drawingArea,
9671                  maxLeft = leftMovement + me.drawingArea;
9672  
9673              me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
9674              // Always vertically in the centre as the text height doesn't change

9675              me.yCenter = Math.round((me.height / 2) + me.top);
9676          },
9677  
9678          getIndexAngle: function(index) {
9679              var angleMultiplier = (Math.PI * 2) / this.getValueCount();
9680              // Start from the top instead of right, so remove a quarter of the circle

9681  
9682              return index * angleMultiplier - (Math.PI / 2);
9683          },
9684          getDistanceFromCenterForValue: function(value) {
9685              var me = this;
9686  
9687              if (value === null) {
9688                  return 0; // null always in center

9689              }
9690  
9691              // Take into account half font size + the yPadding of the top value

9692              var scalingFactor = me.drawingArea / (me.max - me.min);
9693              if (me.options.reverse) {
9694                  return (me.max - value) * scalingFactor;
9695              } else {
9696                  return (value - me.min) * scalingFactor;
9697              }
9698          },
9699          getPointPosition: function(index, distanceFromCenter) {
9700              var me = this;
9701              var thisAngle = me.getIndexAngle(index);
9702              return {
9703                  x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
9704                  y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
9705              };
9706          },
9707          getPointPositionForValue: function(index, value) {
9708              return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
9709          },
9710  
9711          getBasePosition: function() {
9712              var me = this;
9713              var min = me.min;
9714              var max = me.max;
9715  
9716              return me.getPointPositionForValue(0,
9717                  me.beginAtZero? 0:
9718                  min < 0 && max < 0? max :
9719                  min > 0 && max > 0? min :
9720                  0);
9721          },
9722  
9723          draw: function() {
9724              var me = this;
9725              var opts = me.options;
9726              var gridLineOpts = opts.gridLines;
9727              var tickOpts = opts.ticks;
9728              var angleLineOpts = opts.angleLines;
9729              var pointLabelOpts = opts.pointLabels;
9730              var getValueOrDefault = helpers.getValueOrDefault;
9731  
9732              if (opts.display) {
9733                  var ctx = me.ctx;
9734  
9735                  // Tick Font

9736                  var tickFontSize = getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
9737                  var tickFontStyle = getValueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
9738                  var tickFontFamily = getValueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
9739                  var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
9740  
9741                  helpers.each(me.ticks, function(label, index) {
9742                      // Don't draw a centre value (if it is minimum)

9743                      if (index > 0 || opts.reverse) {
9744                          var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
9745                          var yHeight = me.yCenter - yCenterOffset;
9746  
9747                          // Draw circular lines around the scale

9748                          if (gridLineOpts.display && index !== 0) {
9749                              ctx.strokeStyle = helpers.getValueAtIndexOrDefault(gridLineOpts.color, index - 1);
9750                              ctx.lineWidth = helpers.getValueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
9751  
9752                              if (opts.lineArc) {
9753                                  // Draw circular arcs between the points

9754                                  ctx.beginPath();
9755                                  ctx.arc(me.xCenter, me.yCenter, yCenterOffset, 0, Math.PI * 2);
9756                                  ctx.closePath();
9757                                  ctx.stroke();
9758                              } else {
9759                                  // Draw straight lines connecting each index

9760                                  ctx.beginPath();
9761                                  for (var i = 0; i < me.getValueCount(); i++) {
9762                                      var pointPosition = me.getPointPosition(i, yCenterOffset);
9763                                      if (i === 0) {
9764                                          ctx.moveTo(pointPosition.x, pointPosition.y);
9765                                      } else {
9766                                          ctx.lineTo(pointPosition.x, pointPosition.y);
9767                                      }
9768                                  }
9769                                  ctx.closePath();
9770                                  ctx.stroke();
9771                              }
9772                          }
9773  
9774                          if (tickOpts.display) {
9775                              var tickFontColor = getValueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
9776                              ctx.font = tickLabelFont;
9777  
9778                              if (tickOpts.showLabelBackdrop) {
9779                                  var labelWidth = ctx.measureText(label).width;
9780                                  ctx.fillStyle = tickOpts.backdropColor;
9781                                  ctx.fillRect(
9782                                      me.xCenter - labelWidth / 2 - tickOpts.backdropPaddingX,
9783                                      yHeight - tickFontSize / 2 - tickOpts.backdropPaddingY,
9784                                      labelWidth + tickOpts.backdropPaddingX * 2,
9785                                      tickFontSize + tickOpts.backdropPaddingY * 2
9786                                  );
9787                              }
9788  
9789                              ctx.textAlign = 'center';
9790                              ctx.textBaseline = "middle";
9791                              ctx.fillStyle = tickFontColor;
9792                              ctx.fillText(label, me.xCenter, yHeight);
9793                          }
9794                      }
9795                  });
9796  
9797                  if (!opts.lineArc) {
9798                      ctx.lineWidth = angleLineOpts.lineWidth;
9799                      ctx.strokeStyle = angleLineOpts.color;
9800  
9801                      var outerDistance = me.getDistanceFromCenterForValue(opts.reverse ? me.min : me.max);
9802  
9803                      // Point Label Font

9804                      var pointLabelFontSize = getValueOrDefault(pointLabelOpts.fontSize, globalDefaults.defaultFontSize);
9805                      var pointLabeFontStyle = getValueOrDefault(pointLabelOpts.fontStyle, globalDefaults.defaultFontStyle);
9806                      var pointLabeFontFamily = getValueOrDefault(pointLabelOpts.fontFamily, globalDefaults.defaultFontFamily);
9807                      var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
9808  
9809                      for (var i = me.getValueCount() - 1; i >= 0; i--) {
9810                          if (angleLineOpts.display) {
9811                              var outerPosition = me.getPointPosition(i, outerDistance);
9812                              ctx.beginPath();
9813                              ctx.moveTo(me.xCenter, me.yCenter);
9814                              ctx.lineTo(outerPosition.x, outerPosition.y);
9815                              ctx.stroke();
9816                              ctx.closePath();
9817                          }
9818                          // Extra 3px out for some label spacing

9819                          var pointLabelPosition = me.getPointPosition(i, outerDistance + 5);
9820  
9821                          // Keep this in loop since we may support array properties here

9822                          var pointLabelFontColor = getValueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor);
9823                          ctx.font = pointLabeFont;
9824                          ctx.fillStyle = pointLabelFontColor;
9825  
9826                          var pointLabels = me.pointLabels,
9827                              labelsCount = pointLabels.length,
9828                              halfLabelsCount = pointLabels.length / 2,
9829                              quarterLabelsCount = halfLabelsCount / 2,
9830                              upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
9831                              exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
9832                          if (i === 0) {
9833                              ctx.textAlign = 'center';
9834                          } else if (i === halfLabelsCount) {
9835                              ctx.textAlign = 'center';
9836                          } else if (i < halfLabelsCount) {
9837                              ctx.textAlign = 'left';
9838                          } else {
9839                              ctx.textAlign = 'right';
9840                          }
9841  
9842                          // Set the correct text baseline based on outer positioning

9843                          if (exactQuarter) {
9844                              ctx.textBaseline = 'middle';
9845                          } else if (upperHalf) {
9846                              ctx.textBaseline = 'bottom';
9847                          } else {
9848                              ctx.textBaseline = 'top';
9849                          }
9850  
9851                          ctx.fillText(pointLabels[i] ? pointLabels[i] : '', pointLabelPosition.x, pointLabelPosition.y);
9852                      }
9853                  }
9854              }
9855          }
9856      });
9857      Chart.scaleService.registerScaleType("radialLinear", LinearRadialScale, defaultConfig);
9858  
9859  };
9860  
9861  },{}],43:[function(require,module,exports){
9862  /*global window: false */

9863  "use strict";
9864  
9865  var moment = require(1);
9866  moment = typeof(moment) === 'function' ? moment : window.moment;
9867  
9868  module.exports = function(Chart) {
9869  
9870      var helpers = Chart.helpers;
9871      var time = {
9872          units: [{
9873              name: 'millisecond',
9874              steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
9875          }, {
9876              name: 'second',
9877              steps: [1, 2, 5, 10, 30]
9878          }, {
9879              name: 'minute',
9880              steps: [1, 2, 5, 10, 30]
9881          }, {
9882              name: 'hour',
9883              steps: [1, 2, 3, 6, 12]
9884          }, {
9885              name: 'day',
9886              steps: [1, 2, 5]
9887          }, {
9888              name: 'week',
9889              maxStep: 4
9890          }, {
9891              name: 'month',
9892              maxStep: 3
9893          }, {
9894              name: 'quarter',
9895              maxStep: 4
9896          }, {
9897              name: 'year',
9898              maxStep: false
9899          }]
9900      };
9901  
9902      var defaultConfig = {
9903          position: "bottom",
9904  
9905          time: {
9906              parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
9907              format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
9908              unit: false, // false == automatic or override with week, month, year, etc.
9909              round: false, // none, or override with week, month, year, etc.
9910              displayFormat: false, // DEPRECATED
9911              isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
9912  
9913              // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/

9914              displayFormats: {
9915                  'millisecond': 'h:mm:ss.SSS a', // 11:20:01.123 AM,
9916                  'second': 'h:mm:ss a', // 11:20:01 AM
9917                  'minute': 'h:mm:ss a', // 11:20:01 AM
9918                  'hour': 'MMM D, hA', // Sept 4, 5PM
9919                  'day': 'll', // Sep 4 2015
9920                  'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
9921                  'month': 'MMM YYYY', // Sept 2015
9922                  'quarter': '[Q]Q - YYYY', // Q3
9923                  'year': 'YYYY' // 2015
9924              }
9925          },
9926          ticks: {
9927              autoSkip: false
9928          }
9929      };
9930  
9931      var TimeScale = Chart.Scale.extend({
9932          initialize: function() {
9933              if (!moment) {
9934                  throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
9935              }
9936  
9937              Chart.Scale.prototype.initialize.call(this);
9938          },
9939          getLabelMoment: function(datasetIndex, index) {
9940              return this.labelMoments[datasetIndex][index];
9941          },
9942          getMomentStartOf: function(tick) {
9943              var me = this;
9944              if (me.options.time.unit === 'week' && me.options.time.isoWeekday !== false) {
9945                  return tick.clone().startOf('isoWeek').isoWeekday(me.options.time.isoWeekday);
9946              } else {
9947                  return tick.clone().startOf(me.tickUnit);
9948              }
9949          },
9950          determineDataLimits: function() {
9951              var me = this;
9952              me.labelMoments = [];
9953  
9954              // Only parse these once. If the dataset does not have data as x,y pairs, we will use

9955              // these

9956              var scaleLabelMoments = [];
9957              if (me.chart.data.labels && me.chart.data.labels.length > 0) {
9958                  helpers.each(me.chart.data.labels, function(label, index) {
9959                      var labelMoment = me.parseTime(label);
9960  
9961                      if (labelMoment.isValid()) {
9962                          if (me.options.time.round) {
9963                              labelMoment.startOf(me.options.time.round);
9964                          }
9965                          scaleLabelMoments.push(labelMoment);
9966                      }
9967                  }, me);
9968  
9969                  me.firstTick = moment.min.call(me, scaleLabelMoments);
9970                  me.lastTick = moment.max.call(me, scaleLabelMoments);
9971              } else {
9972                  me.firstTick = null;
9973                  me.lastTick = null;
9974              }
9975  
9976              helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) {
9977                  var momentsForDataset = [];
9978                  var datasetVisible = me.chart.isDatasetVisible(datasetIndex);
9979  
9980                  if (typeof dataset.data[0] === 'object' && dataset.data[0] !== null) {
9981                      helpers.each(dataset.data, function(value, index) {
9982                          var labelMoment = me.parseTime(me.getRightValue(value));
9983  
9984                          if (labelMoment.isValid()) {
9985                              if (me.options.time.round) {
9986                                  labelMoment.startOf(me.options.time.round);
9987                              }
9988                              momentsForDataset.push(labelMoment);
9989  
9990                              if (datasetVisible) {
9991                                  // May have gone outside the scale ranges, make sure we keep the first and last ticks updated

9992                                  me.firstTick = me.firstTick !== null ? moment.min(me.firstTick, labelMoment) : labelMoment;
9993                                  me.lastTick = me.lastTick !== null ? moment.max(me.lastTick, labelMoment) : labelMoment;
9994                              }
9995                          }
9996                      }, me);
9997                  } else {
9998                      // We have no labels. Use the ones from the scale

9999                      momentsForDataset = scaleLabelMoments;
10000                  }
10001  
10002                  me.labelMoments.push(momentsForDataset);
10003              }, me);
10004  
10005              // Set these after we've done all the data

10006              if (me.options.time.min) {
10007                  me.firstTick = me.parseTime(me.options.time.min);
10008              }
10009  
10010              if (me.options.time.max) {
10011                  me.lastTick = me.parseTime(me.options.time.max);
10012              }
10013  
10014              // We will modify these, so clone for later

10015              me.firstTick = (me.firstTick || moment()).clone();
10016              me.lastTick = (me.lastTick || moment()).clone();
10017          },
10018          buildTicks: function(index) {
10019              var me = this;
10020  
10021              me.ctx.save();
10022              var tickFontSize = helpers.getValueOrDefault(me.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
10023              var tickFontStyle = helpers.getValueOrDefault(me.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
10024              var tickFontFamily = helpers.getValueOrDefault(me.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
10025              var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
10026              me.ctx.font = tickLabelFont;
10027  
10028              me.ticks = [];
10029              me.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step

10030              me.scaleSizeInUnits = 0; // How large the scale is in the base unit (seconds, minutes, etc)

10031  
10032              // Set unit override if applicable

10033              if (me.options.time.unit) {
10034                  me.tickUnit = me.options.time.unit || 'day';
10035                  me.displayFormat = me.options.time.displayFormats[me.tickUnit];
10036                  me.scaleSizeInUnits = me.lastTick.diff(me.firstTick, me.tickUnit, true);
10037                  me.unitScale = helpers.getValueOrDefault(me.options.time.unitStepSize, 1);
10038              } else {
10039                  // Determine the smallest needed unit of the time

10040                  var innerWidth = me.isHorizontal() ? me.width - (me.paddingLeft + me.paddingRight) : me.height - (me.paddingTop + me.paddingBottom);
10041  
10042                  // Crude approximation of what the label length might be

10043                  var tempFirstLabel = me.tickFormatFunction(me.firstTick, 0, []);
10044                  var tickLabelWidth = me.ctx.measureText(tempFirstLabel).width;
10045                  var cosRotation = Math.cos(helpers.toRadians(me.options.ticks.maxRotation));
10046                  var sinRotation = Math.sin(helpers.toRadians(me.options.ticks.maxRotation));
10047                  tickLabelWidth = (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
10048                  var labelCapacity = innerWidth / (tickLabelWidth);
10049  
10050                  // Start as small as possible

10051                  me.tickUnit = 'millisecond';
10052                  me.scaleSizeInUnits = me.lastTick.diff(me.firstTick, me.tickUnit, true);
10053                  me.displayFormat = me.options.time.displayFormats[me.tickUnit];
10054  
10055                  var unitDefinitionIndex = 0;
10056                  var unitDefinition = time.units[unitDefinitionIndex];
10057  
10058                  // While we aren't ideal and we don't have units left

10059                  while (unitDefinitionIndex < time.units.length) {
10060                      // Can we scale this unit. If `false` we can scale infinitely

10061                      me.unitScale = 1;
10062  
10063                      if (helpers.isArray(unitDefinition.steps) && Math.ceil(me.scaleSizeInUnits / labelCapacity) < helpers.max(unitDefinition.steps)) {
10064                          // Use one of the prefedined steps

10065                          for (var idx = 0; idx < unitDefinition.steps.length; ++idx) {
10066                              if (unitDefinition.steps[idx] >= Math.ceil(me.scaleSizeInUnits / labelCapacity)) {
10067                                  me.unitScale = helpers.getValueOrDefault(me.options.time.unitStepSize, unitDefinition.steps[idx]);
10068                                  break;
10069                              }
10070                          }
10071  
10072                          break;
10073                      } else if ((unitDefinition.maxStep === false) || (Math.ceil(me.scaleSizeInUnits / labelCapacity) < unitDefinition.maxStep)) {
10074                          // We have a max step. Scale this unit

10075                          me.unitScale = helpers.getValueOrDefault(me.options.time.unitStepSize, Math.ceil(me.scaleSizeInUnits / labelCapacity));
10076                          break;
10077                      } else {
10078                          // Move to the next unit up

10079                          ++unitDefinitionIndex;
10080                          unitDefinition = time.units[unitDefinitionIndex];
10081  
10082                          me.tickUnit = unitDefinition.name;
10083                          var leadingUnitBuffer = me.firstTick.diff(me.getMomentStartOf(me.firstTick), me.tickUnit, true);
10084                          var trailingUnitBuffer = me.getMomentStartOf(me.lastTick.clone().add(1, me.tickUnit)).diff(me.lastTick, me.tickUnit, true);
10085                          me.scaleSizeInUnits = me.lastTick.diff(me.firstTick, me.tickUnit, true) + leadingUnitBuffer + trailingUnitBuffer;
10086                          me.displayFormat = me.options.time.displayFormats[unitDefinition.name];
10087                      }
10088                  }
10089              }
10090  
10091              var roundedStart;
10092  
10093              // Only round the first tick if we have no hard minimum

10094              if (!me.options.time.min) {
10095                  me.firstTick = me.getMomentStartOf(me.firstTick);
10096                  roundedStart = me.firstTick;
10097              } else {
10098                  roundedStart = me.getMomentStartOf(me.firstTick);
10099              }
10100  
10101              // Only round the last tick if we have no hard maximum

10102              if (!me.options.time.max) {
10103                  var roundedEnd = me.getMomentStartOf(me.lastTick);
10104                  if (roundedEnd.diff(me.lastTick, me.tickUnit, true) !== 0) {
10105                      // Do not use end of because we need me to be in the next time unit

10106                      me.lastTick = me.getMomentStartOf(me.lastTick.add(1, me.tickUnit));
10107                  }
10108              }
10109  
10110              me.smallestLabelSeparation = me.width;
10111  
10112              helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) {
10113                  for (var i = 1; i < me.labelMoments[datasetIndex].length; i++) {
10114                      me.smallestLabelSeparation = Math.min(me.smallestLabelSeparation, me.labelMoments[datasetIndex][i].diff(me.labelMoments[datasetIndex][i - 1], me.tickUnit, true));
10115                  }
10116              }, me);
10117  
10118              // Tick displayFormat override

10119              if (me.options.time.displayFormat) {
10120                  me.displayFormat = me.options.time.displayFormat;
10121              }
10122  
10123              // first tick. will have been rounded correctly if options.time.min is not specified

10124              me.ticks.push(me.firstTick.clone());
10125  
10126              // For every unit in between the first and last moment, create a moment and add it to the ticks tick

10127              for (var i = 1; i <= me.scaleSizeInUnits; ++i) {
10128                  var newTick = roundedStart.clone().add(i, me.tickUnit);
10129  
10130                  // Are we greater than the max time

10131                  if (me.options.time.max && newTick.diff(me.lastTick, me.tickUnit, true) >= 0) {
10132                      break;
10133                  }
10134  
10135                  if (i % me.unitScale === 0) {
10136                      me.ticks.push(newTick);
10137                  }
10138              }
10139  
10140              // Always show the right tick

10141              var diff = me.ticks[me.ticks.length - 1].diff(me.lastTick, me.tickUnit);
10142              if (diff !== 0 || me.scaleSizeInUnits === 0) {
10143                  // this is a weird case. If the <max> option is the same as the end option, we can't just diff the times because the tick was created from the roundedStart

10144                  // but the last tick was not rounded.

10145                  if (me.options.time.max) {
10146                      me.ticks.push(me.lastTick.clone());
10147                      me.scaleSizeInUnits = me.lastTick.diff(me.ticks[0], me.tickUnit, true);
10148                  } else {
10149                      me.ticks.push(me.lastTick.clone());
10150                      me.scaleSizeInUnits = me.lastTick.diff(me.firstTick, me.tickUnit, true);
10151                  }
10152              }
10153  
10154              me.ctx.restore();
10155          },
10156          // Get tooltip label

10157          getLabelForIndex: function(index, datasetIndex) {
10158              var me = this;
10159              var label = me.chart.data.labels && index < me.chart.data.labels.length ? me.chart.data.labels[index] : '';
10160  
10161              if (typeof me.chart.data.datasets[datasetIndex].data[0] === 'object') {
10162                  label = me.getRightValue(me.chart.data.datasets[datasetIndex].data[index]);
10163              }
10164  
10165              // Format nicely

10166              if (me.options.time.tooltipFormat) {
10167                  label = me.parseTime(label).format(me.options.time.tooltipFormat);
10168              }
10169  
10170              return label;
10171          },
10172          // Function to format an individual tick mark

10173          tickFormatFunction: function tickFormatFunction(tick, index, ticks) {
10174              var formattedTick = tick.format(this.displayFormat);
10175              var tickOpts = this.options.ticks;
10176              var callback = helpers.getValueOrDefault(tickOpts.callback, tickOpts.userCallback);
10177  
10178              if (callback) {
10179                  return callback(formattedTick, index, ticks);
10180              } else {
10181                  return formattedTick;
10182              }
10183          },
10184          convertTicksToLabels: function() {
10185              var me = this;
10186              me.tickMoments = me.ticks;
10187              me.ticks = me.ticks.map(me.tickFormatFunction, me);
10188          },
10189          getPixelForValue: function(value, index, datasetIndex, includeOffset) {
10190              var me = this;
10191              var labelMoment = value && value.isValid && value.isValid() ? value : me.getLabelMoment(datasetIndex, index);
10192  
10193              if (labelMoment) {
10194                  var offset = labelMoment.diff(me.firstTick, me.tickUnit, true);
10195  
10196                  var decimal = offset / me.scaleSizeInUnits;
10197  
10198                  if (me.isHorizontal()) {
10199                      var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
10200                      var valueWidth = innerWidth / Math.max(me.ticks.length - 1, 1);
10201                      var valueOffset = (innerWidth * decimal) + me.paddingLeft;
10202  
10203                      return me.left + Math.round(valueOffset);
10204                  } else {
10205                      var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
10206                      var valueHeight = innerHeight / Math.max(me.ticks.length - 1, 1);
10207                      var heightOffset = (innerHeight * decimal) + me.paddingTop;
10208  
10209                      return me.top + Math.round(heightOffset);
10210                  }
10211              }
10212          },
10213          getPixelForTick: function(index, includeOffset) {
10214              return this.getPixelForValue(this.tickMoments[index], null, null, includeOffset);
10215          },
10216          getValueForPixel: function(pixel) {
10217              var me = this;
10218              var innerDimension = me.isHorizontal() ? me.width - (me.paddingLeft + me.paddingRight) : me.height - (me.paddingTop + me.paddingBottom);
10219              var offset = (pixel - (me.isHorizontal() ? me.left + me.paddingLeft : me.top + me.paddingTop)) / innerDimension;
10220              offset *= me.scaleSizeInUnits;
10221              return me.firstTick.clone().add(moment.duration(offset, me.tickUnit).asSeconds(), 'seconds');
10222          },
10223          parseTime: function(label) {
10224              var me = this;
10225              if (typeof me.options.time.parser === 'string') {
10226                  return moment(label, me.options.time.parser);
10227              }
10228              if (typeof me.options.time.parser === 'function') {
10229                  return me.options.time.parser(label);
10230              }
10231              // Date objects

10232              if (typeof label.getMonth === 'function' || typeof label === 'number') {
10233                  return moment(label);
10234              }
10235              // Moment support

10236              if (label.isValid && label.isValid()) {
10237                  return label;
10238              }
10239              // Custom parsing (return an instance of moment)

10240              if (typeof me.options.time.format !== 'string' && me.options.time.format.call) {
10241                  console.warn("options.time.format is deprecated and replaced by options.time.parser. See http://nnnick.github.io/Chart.js/docs-v2/#scales-time-scale");
10242                  return me.options.time.format(label);
10243              }
10244              // Moment format parsing

10245              return moment(label, me.options.time.format);
10246          }
10247      });
10248      Chart.scaleService.registerScaleType("time", TimeScale, defaultConfig);
10249  
10250  };
10251  
10252  },{"1":1}]},{},[7])(7)
10253  });


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1