/*! * Chart.js * http://chartjs.org/ * Version: 2.5.0 * * Copyright 2017 Nick Downie * Released under the MIT license * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md */ (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 lum2) { return (lum1 + 0.05) / (lum2 + 0.05); } return (lum2 + 0.05) / (lum1 + 0.05); }, level: function (color2) { var contrastRatio = this.contrast(color2); if (contrastRatio >= 7.1) { return 'AAA'; } return (contrastRatio >= 4.5) ? 'AA' : ''; }, dark: function () { // YIQ equation from http://24ways.org/2010/calculating-color-contrast var rgb = this.values.rgb; var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000; return yiq < 128; }, light: function () { return !this.dark(); }, negate: function () { var rgb = []; for (var i = 0; i < 3; i++) { rgb[i] = 255 - this.values.rgb[i]; } this.setValues('rgb', rgb); return this; }, lighten: function (ratio) { var hsl = this.values.hsl; hsl[2] += hsl[2] * ratio; this.setValues('hsl', hsl); return this; }, darken: function (ratio) { var hsl = this.values.hsl; hsl[2] -= hsl[2] * ratio; this.setValues('hsl', hsl); return this; }, saturate: function (ratio) { var hsl = this.values.hsl; hsl[1] += hsl[1] * ratio; this.setValues('hsl', hsl); return this; }, desaturate: function (ratio) { var hsl = this.values.hsl; hsl[1] -= hsl[1] * ratio; this.setValues('hsl', hsl); return this; }, whiten: function (ratio) { var hwb = this.values.hwb; hwb[1] += hwb[1] * ratio; this.setValues('hwb', hwb); return this; }, blacken: function (ratio) { var hwb = this.values.hwb; hwb[2] += hwb[2] * ratio; this.setValues('hwb', hwb); return this; }, greyscale: function () { var rgb = this.values.rgb; // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11; this.setValues('rgb', [val, val, val]); return this; }, clearer: function (ratio) { var alpha = this.values.alpha; this.setValues('alpha', alpha - (alpha * ratio)); return this; }, opaquer: function (ratio) { var alpha = this.values.alpha; this.setValues('alpha', alpha + (alpha * ratio)); return this; }, rotate: function (degrees) { var hsl = this.values.hsl; var hue = (hsl[0] + degrees) % 360; hsl[0] = hue < 0 ? 360 + hue : hue; this.setValues('hsl', hsl); return this; }, /** * Ported from sass implementation in C * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209 */ mix: function (mixinColor, weight) { var color1 = this; var color2 = mixinColor; var p = weight === undefined ? 0.5 : weight; var w = 2 * p - 1; var a = color1.alpha() - color2.alpha(); var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; return this .rgb( w1 * color1.red() + w2 * color2.red(), w1 * color1.green() + w2 * color2.green(), w1 * color1.blue() + w2 * color2.blue() ) .alpha(color1.alpha() * p + color2.alpha() * (1 - p)); }, toJSON: function () { return this.rgb(); }, clone: function () { // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify, // making the final build way to big to embed in Chart.js. So let's do it manually, // assuming that values to clone are 1 dimension arrays containing only numbers, // except 'alpha' which is a number. var result = new Color(); var source = this.values; var target = result.values; var value, type; for (var prop in source) { if (source.hasOwnProperty(prop)) { value = source[prop]; type = ({}).toString.call(value); if (type === '[object Array]') { target[prop] = value.slice(0); } else if (type === '[object Number]') { target[prop] = value; } else { console.error('unexpected color value:', value); } } } return result; } }; Color.prototype.spaces = { rgb: ['red', 'green', 'blue'], hsl: ['hue', 'saturation', 'lightness'], hsv: ['hue', 'saturation', 'value'], hwb: ['hue', 'whiteness', 'blackness'], cmyk: ['cyan', 'magenta', 'yellow', 'black'] }; Color.prototype.maxes = { rgb: [255, 255, 255], hsl: [360, 100, 100], hsv: [360, 100, 100], hwb: [360, 100, 100], cmyk: [100, 100, 100, 100] }; Color.prototype.getValues = function (space) { var values = this.values; var vals = {}; for (var i = 0; i < space.length; i++) { vals[space.charAt(i)] = values[space][i]; } if (values.alpha !== 1) { vals.a = values.alpha; } // {r: 255, g: 255, b: 255, a: 0.4} return vals; }; Color.prototype.setValues = function (space, vals) { var values = this.values; var spaces = this.spaces; var maxes = this.maxes; var alpha = 1; var i; if (space === 'alpha') { alpha = vals; } else if (vals.length) { // [10, 10, 10] values[space] = vals.slice(0, space.length); alpha = vals[space.length]; } else if (vals[space.charAt(0)] !== undefined) { // {r: 10, g: 10, b: 10} for (i = 0; i < space.length; i++) { values[space][i] = vals[space.charAt(i)]; } alpha = vals.a; } else if (vals[spaces[space][0]] !== undefined) { // {red: 10, green: 10, blue: 10} var chans = spaces[space]; for (i = 0; i < space.length; i++) { values[space][i] = vals[chans[i]]; } alpha = vals.alpha; } values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha))); if (space === 'alpha') { return false; } var capped; // cap values of the space prior converting all values for (i = 0; i < space.length; i++) { capped = Math.max(0, Math.min(maxes[space][i], values[space][i])); values[space][i] = Math.round(capped); } // convert to all the other color spaces for (var sname in spaces) { if (sname !== space) { values[sname] = convert[space][sname](values[space]); } } return true; }; Color.prototype.setSpace = function (space, args) { var vals = args[0]; if (vals === undefined) { // color.rgb() return this.getValues(space); } // color.rgb(10, 10, 10) if (typeof vals === 'number') { vals = Array.prototype.slice.call(args); } this.setValues(space, vals); return this; }; Color.prototype.setChannel = function (space, index, val) { var svalues = this.values[space]; if (val === undefined) { // color.red() return svalues[index]; } else if (val === svalues[index]) { // color.red(color.red()) return this; } // color.red(100) svalues[index] = val; this.setValues(space, svalues); return this; }; if (typeof window !== 'undefined') { window.Color = Color; } module.exports = Color; },{"2":2,"5":5}],4:[function(require,module,exports){ /* MIT license */ module.exports = { rgb2hsl: rgb2hsl, rgb2hsv: rgb2hsv, rgb2hwb: rgb2hwb, rgb2cmyk: rgb2cmyk, rgb2keyword: rgb2keyword, rgb2xyz: rgb2xyz, rgb2lab: rgb2lab, rgb2lch: rgb2lch, hsl2rgb: hsl2rgb, hsl2hsv: hsl2hsv, hsl2hwb: hsl2hwb, hsl2cmyk: hsl2cmyk, hsl2keyword: hsl2keyword, hsv2rgb: hsv2rgb, hsv2hsl: hsv2hsl, hsv2hwb: hsv2hwb, hsv2cmyk: hsv2cmyk, hsv2keyword: hsv2keyword, hwb2rgb: hwb2rgb, hwb2hsl: hwb2hsl, hwb2hsv: hwb2hsv, hwb2cmyk: hwb2cmyk, hwb2keyword: hwb2keyword, cmyk2rgb: cmyk2rgb, cmyk2hsl: cmyk2hsl, cmyk2hsv: cmyk2hsv, cmyk2hwb: cmyk2hwb, cmyk2keyword: cmyk2keyword, keyword2rgb: keyword2rgb, keyword2hsl: keyword2hsl, keyword2hsv: keyword2hsv, keyword2hwb: keyword2hwb, keyword2cmyk: keyword2cmyk, keyword2lab: keyword2lab, keyword2xyz: keyword2xyz, xyz2rgb: xyz2rgb, xyz2lab: xyz2lab, xyz2lch: xyz2lch, lab2xyz: lab2xyz, lab2rgb: lab2rgb, lab2lch: lab2lch, lch2lab: lch2lab, lch2xyz: lch2xyz, lch2rgb: lch2rgb } function rgb2hsl(rgb) { var r = rgb[0]/255, g = rgb[1]/255, b = rgb[2]/255, min = Math.min(r, g, b), max = Math.max(r, g, b), delta = max - min, h, s, l; if (max == min) h = 0; else if (r == max) h = (g - b) / delta; else if (g == max) h = 2 + (b - r) / delta; else if (b == max) h = 4 + (r - g)/ delta; h = Math.min(h * 60, 360); if (h < 0) h += 360; l = (min + max) / 2; if (max == min) s = 0; else if (l <= 0.5) s = delta / (max + min); else s = delta / (2 - max - min); return [h, s * 100, l * 100]; } function rgb2hsv(rgb) { var r = rgb[0], g = rgb[1], b = rgb[2], min = Math.min(r, g, b), max = Math.max(r, g, b), delta = max - min, h, s, v; if (max == 0) s = 0; else s = (delta/max * 1000)/10; if (max == min) h = 0; else if (r == max) h = (g - b) / delta; else if (g == max) h = 2 + (b - r) / delta; else if (b == max) h = 4 + (r - g) / delta; h = Math.min(h * 60, 360); if (h < 0) h += 360; v = ((max / 255) * 1000) / 10; return [h, s, v]; } function rgb2hwb(rgb) { var r = rgb[0], g = rgb[1], b = rgb[2], h = rgb2hsl(rgb)[0], w = 1/255 * Math.min(r, Math.min(g, b)), b = 1 - 1/255 * Math.max(r, Math.max(g, b)); return [h, w * 100, b * 100]; } function rgb2cmyk(rgb) { var r = rgb[0] / 255, g = rgb[1] / 255, b = rgb[2] / 255, c, m, y, k; k = Math.min(1 - r, 1 - g, 1 - b); c = (1 - r - k) / (1 - k) || 0; m = (1 - g - k) / (1 - k) || 0; y = (1 - b - k) / (1 - k) || 0; return [c * 100, m * 100, y * 100, k * 100]; } function rgb2keyword(rgb) { return reverseKeywords[JSON.stringify(rgb)]; } function rgb2xyz(rgb) { var r = rgb[0] / 255, g = rgb[1] / 255, b = rgb[2] / 255; // assume sRGB r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92); g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92); b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92); var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); return [x * 100, y *100, z * 100]; } function rgb2lab(rgb) { var xyz = rgb2xyz(rgb), x = xyz[0], y = xyz[1], z = xyz[2], l, a, b; x /= 95.047; y /= 100; z /= 108.883; x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); l = (116 * y) - 16; a = 500 * (x - y); b = 200 * (y - z); return [l, a, b]; } function rgb2lch(args) { return lab2lch(rgb2lab(args)); } function hsl2rgb(hsl) { var h = hsl[0] / 360, s = hsl[1] / 100, l = hsl[2] / 100, t1, t2, t3, rgb, val; if (s == 0) { val = l * 255; return [val, val, val]; } if (l < 0.5) t2 = l * (1 + s); else t2 = l + s - l * s; t1 = 2 * l - t2; rgb = [0, 0, 0]; for (var i = 0; i < 3; i++) { t3 = h + 1 / 3 * - (i - 1); t3 < 0 && t3++; t3 > 1 && t3--; if (6 * t3 < 1) val = t1 + (t2 - t1) * 6 * t3; else if (2 * t3 < 1) val = t2; else if (3 * t3 < 2) val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; else val = t1; rgb[i] = val * 255; } return rgb; } function hsl2hsv(hsl) { var h = hsl[0], s = hsl[1] / 100, l = hsl[2] / 100, sv, v; if(l === 0) { // no need to do calc on black // also avoids divide by 0 error return [0, 0, 0]; } l *= 2; s *= (l <= 1) ? l : 2 - l; v = (l + s) / 2; sv = (2 * s) / (l + s); return [h, sv * 100, v * 100]; } function hsl2hwb(args) { return rgb2hwb(hsl2rgb(args)); } function hsl2cmyk(args) { return rgb2cmyk(hsl2rgb(args)); } function hsl2keyword(args) { return rgb2keyword(hsl2rgb(args)); } function hsv2rgb(hsv) { var h = hsv[0] / 60, s = hsv[1] / 100, v = hsv[2] / 100, hi = Math.floor(h) % 6; var f = h - Math.floor(h), p = 255 * v * (1 - s), q = 255 * v * (1 - (s * f)), t = 255 * v * (1 - (s * (1 - f))), v = 255 * v; switch(hi) { case 0: return [v, t, p]; case 1: return [q, v, p]; case 2: return [p, v, t]; case 3: return [p, q, v]; case 4: return [t, p, v]; case 5: return [v, p, q]; } } function hsv2hsl(hsv) { var h = hsv[0], s = hsv[1] / 100, v = hsv[2] / 100, sl, l; l = (2 - s) * v; sl = s * v; sl /= (l <= 1) ? l : 2 - l; sl = sl || 0; l /= 2; return [h, sl * 100, l * 100]; } function hsv2hwb(args) { return rgb2hwb(hsv2rgb(args)) } function hsv2cmyk(args) { return rgb2cmyk(hsv2rgb(args)); } function hsv2keyword(args) { return rgb2keyword(hsv2rgb(args)); } // http://dev.w3.org/csswg/css-color/#hwb-to-rgb function hwb2rgb(hwb) { var h = hwb[0] / 360, wh = hwb[1] / 100, bl = hwb[2] / 100, ratio = wh + bl, i, v, f, n; // wh + bl cant be > 1 if (ratio > 1) { wh /= ratio; bl /= ratio; } i = Math.floor(6 * h); v = 1 - bl; f = 6 * h - i; if ((i & 0x01) != 0) { f = 1 - f; } n = wh + f * (v - wh); // linear interpolation switch (i) { default: case 6: case 0: r = v; g = n; b = wh; break; case 1: r = n; g = v; b = wh; break; case 2: r = wh; g = v; b = n; break; case 3: r = wh; g = n; b = v; break; case 4: r = n; g = wh; b = v; break; case 5: r = v; g = wh; b = n; break; } return [r * 255, g * 255, b * 255]; } function hwb2hsl(args) { return rgb2hsl(hwb2rgb(args)); } function hwb2hsv(args) { return rgb2hsv(hwb2rgb(args)); } function hwb2cmyk(args) { return rgb2cmyk(hwb2rgb(args)); } function hwb2keyword(args) { return rgb2keyword(hwb2rgb(args)); } function cmyk2rgb(cmyk) { var c = cmyk[0] / 100, m = cmyk[1] / 100, y = cmyk[2] / 100, k = cmyk[3] / 100, r, g, b; r = 1 - Math.min(1, c * (1 - k) + k); g = 1 - Math.min(1, m * (1 - k) + k); b = 1 - Math.min(1, y * (1 - k) + k); return [r * 255, g * 255, b * 255]; } function cmyk2hsl(args) { return rgb2hsl(cmyk2rgb(args)); } function cmyk2hsv(args) { return rgb2hsv(cmyk2rgb(args)); } function cmyk2hwb(args) { return rgb2hwb(cmyk2rgb(args)); } function cmyk2keyword(args) { return rgb2keyword(cmyk2rgb(args)); } function xyz2rgb(xyz) { var x = xyz[0] / 100, y = xyz[1] / 100, z = xyz[2] / 100, r, g, b; r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); // assume sRGB r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055) : r = (r * 12.92); g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055) : g = (g * 12.92); b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055) : b = (b * 12.92); r = Math.min(Math.max(0, r), 1); g = Math.min(Math.max(0, g), 1); b = Math.min(Math.max(0, b), 1); return [r * 255, g * 255, b * 255]; } function xyz2lab(xyz) { var x = xyz[0], y = xyz[1], z = xyz[2], l, a, b; x /= 95.047; y /= 100; z /= 108.883; x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); l = (116 * y) - 16; a = 500 * (x - y); b = 200 * (y - z); return [l, a, b]; } function xyz2lch(args) { return lab2lch(xyz2lab(args)); } function lab2xyz(lab) { var l = lab[0], a = lab[1], b = lab[2], x, y, z, y2; if (l <= 8) { y = (l * 100) / 903.3; y2 = (7.787 * (y / 100)) + (16 / 116); } else { y = 100 * Math.pow((l + 16) / 116, 3); y2 = Math.pow(y / 100, 1/3); } x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3); z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3); return [x, y, z]; } function lab2lch(lab) { var l = lab[0], a = lab[1], b = lab[2], hr, h, c; hr = Math.atan2(b, a); h = hr * 360 / 2 / Math.PI; if (h < 0) { h += 360; } c = Math.sqrt(a * a + b * b); return [l, c, h]; } function lab2rgb(args) { return xyz2rgb(lab2xyz(args)); } function lch2lab(lch) { var l = lch[0], c = lch[1], h = lch[2], a, b, hr; hr = h / 360 * 2 * Math.PI; a = c * Math.cos(hr); b = c * Math.sin(hr); return [l, a, b]; } function lch2xyz(args) { return lab2xyz(lch2lab(args)); } function lch2rgb(args) { return lab2rgb(lch2lab(args)); } function keyword2rgb(keyword) { return cssKeywords[keyword]; } function keyword2hsl(args) { return rgb2hsl(keyword2rgb(args)); } function keyword2hsv(args) { return rgb2hsv(keyword2rgb(args)); } function keyword2hwb(args) { return rgb2hwb(keyword2rgb(args)); } function keyword2cmyk(args) { return rgb2cmyk(keyword2rgb(args)); } function keyword2lab(args) { return rgb2lab(keyword2rgb(args)); } function keyword2xyz(args) { return rgb2xyz(keyword2rgb(args)); } var cssKeywords = { aliceblue: [240,248,255], antiquewhite: [250,235,215], aqua: [0,255,255], aquamarine: [127,255,212], azure: [240,255,255], beige: [245,245,220], bisque: [255,228,196], black: [0,0,0], blanchedalmond: [255,235,205], blue: [0,0,255], blueviolet: [138,43,226], brown: [165,42,42], burlywood: [222,184,135], cadetblue: [95,158,160], chartreuse: [127,255,0], chocolate: [210,105,30], coral: [255,127,80], cornflowerblue: [100,149,237], cornsilk: [255,248,220], crimson: [220,20,60], cyan: [0,255,255], darkblue: [0,0,139], darkcyan: [0,139,139], darkgoldenrod: [184,134,11], darkgray: [169,169,169], darkgreen: [0,100,0], darkgrey: [169,169,169], darkkhaki: [189,183,107], darkmagenta: [139,0,139], darkolivegreen: [85,107,47], darkorange: [255,140,0], darkorchid: [153,50,204], darkred: [139,0,0], darksalmon: [233,150,122], darkseagreen: [143,188,143], darkslateblue: [72,61,139], darkslategray: [47,79,79], darkslategrey: [47,79,79], darkturquoise: [0,206,209], darkviolet: [148,0,211], deeppink: [255,20,147], deepskyblue: [0,191,255], dimgray: [105,105,105], dimgrey: [105,105,105], dodgerblue: [30,144,255], firebrick: [178,34,34], floralwhite: [255,250,240], forestgreen: [34,139,34], fuchsia: [255,0,255], gainsboro: [220,220,220], ghostwhite: [248,248,255], gold: [255,215,0], goldenrod: [218,165,32], gray: [128,128,128], green: [0,128,0], greenyellow: [173,255,47], grey: [128,128,128], honeydew: [240,255,240], hotpink: [255,105,180], indianred: [205,92,92], indigo: [75,0,130], ivory: [255,255,240], khaki: [240,230,140], lavender: [230,230,250], lavenderblush: [255,240,245], lawngreen: [124,252,0], lemonchiffon: [255,250,205], lightblue: [173,216,230], lightcoral: [240,128,128], lightcyan: [224,255,255], lightgoldenrodyellow: [250,250,210], lightgray: [211,211,211], lightgreen: [144,238,144], lightgrey: [211,211,211], lightpink: [255,182,193], lightsalmon: [255,160,122], lightseagreen: [32,178,170], lightskyblue: [135,206,250], lightslategray: [119,136,153], lightslategrey: [119,136,153], lightsteelblue: [176,196,222], lightyellow: [255,255,224], lime: [0,255,0], limegreen: [50,205,50], linen: [250,240,230], magenta: [255,0,255], maroon: [128,0,0], mediumaquamarine: [102,205,170], mediumblue: [0,0,205], mediumorchid: [186,85,211], mediumpurple: [147,112,219], mediumseagreen: [60,179,113], mediumslateblue: [123,104,238], mediumspringgreen: [0,250,154], mediumturquoise: [72,209,204], mediumvioletred: [199,21,133], midnightblue: [25,25,112], mintcream: [245,255,250], mistyrose: [255,228,225], moccasin: [255,228,181], navajowhite: [255,222,173], navy: [0,0,128], oldlace: [253,245,230], olive: [128,128,0], olivedrab: [107,142,35], orange: [255,165,0], orangered: [255,69,0], orchid: [218,112,214], palegoldenrod: [238,232,170], palegreen: [152,251,152], paleturquoise: [175,238,238], palevioletred: [219,112,147], papayawhip: [255,239,213], peachpuff: [255,218,185], peru: [205,133,63], pink: [255,192,203], plum: [221,160,221], powderblue: [176,224,230], purple: [128,0,128], rebeccapurple: [102, 51, 153], red: [255,0,0], rosybrown: [188,143,143], royalblue: [65,105,225], saddlebrown: [139,69,19], salmon: [250,128,114], sandybrown: [244,164,96], seagreen: [46,139,87], seashell: [255,245,238], sienna: [160,82,45], silver: [192,192,192], skyblue: [135,206,235], slateblue: [106,90,205], slategray: [112,128,144], slategrey: [112,128,144], snow: [255,250,250], springgreen: [0,255,127], steelblue: [70,130,180], tan: [210,180,140], teal: [0,128,128], thistle: [216,191,216], tomato: [255,99,71], turquoise: [64,224,208], violet: [238,130,238], wheat: [245,222,179], white: [255,255,255], whitesmoke: [245,245,245], yellow: [255,255,0], yellowgreen: [154,205,50] }; var reverseKeywords = {}; for (var key in cssKeywords) { reverseKeywords[JSON.stringify(cssKeywords[key])] = key; } },{}],5:[function(require,module,exports){ var conversions = require(4); var convert = function() { return new Converter(); } for (var func in conversions) { // export Raw versions convert[func + "Raw"] = (function(func) { // accept array or plain args return function(arg) { if (typeof arg == "number") arg = Array.prototype.slice.call(arguments); return conversions[func](arg); } })(func); var pair = /(\w+)2(\w+)/.exec(func), from = pair[1], to = pair[2]; // export rgb2hsl and ["rgb"]["hsl"] convert[from] = convert[from] || {}; convert[from][to] = convert[func] = (function(func) { return function(arg) { if (typeof arg == "number") arg = Array.prototype.slice.call(arguments); var val = conversions[func](arg); if (typeof val == "string" || val === undefined) return val; // keyword for (var i = 0; i < val.length; i++) val[i] = Math.round(val[i]); return val; } })(func); } /* Converter does lazy conversion and caching */ var Converter = function() { this.convs = {}; }; /* Either get the values for a space or set the values for a space, depending on args */ Converter.prototype.routeSpace = function(space, args) { var values = args[0]; if (values === undefined) { // color.rgb() return this.getValues(space); } // color.rgb(10, 10, 10) if (typeof values == "number") { values = Array.prototype.slice.call(args); } return this.setValues(space, values); }; /* Set the values for a space, invalidating cache */ Converter.prototype.setValues = function(space, values) { this.space = space; this.convs = {}; this.convs[space] = values; return this; }; /* Get the values for a space. If there's already a conversion for the space, fetch it, otherwise compute it */ Converter.prototype.getValues = function(space) { var vals = this.convs[space]; if (!vals) { var fspace = this.space, from = this.convs[fspace]; vals = convert[fspace][space](from); this.convs[space] = vals; } return vals; }; ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) { Converter.prototype[space] = function(vals) { return this.routeSpace(space, arguments); } }); module.exports = convert; },{"4":4}],6:[function(require,module,exports){ module.exports = { "aliceblue": [240, 248, 255], "antiquewhite": [250, 235, 215], "aqua": [0, 255, 255], "aquamarine": [127, 255, 212], "azure": [240, 255, 255], "beige": [245, 245, 220], "bisque": [255, 228, 196], "black": [0, 0, 0], "blanchedalmond": [255, 235, 205], "blue": [0, 0, 255], "blueviolet": [138, 43, 226], "brown": [165, 42, 42], "burlywood": [222, 184, 135], "cadetblue": [95, 158, 160], "chartreuse": [127, 255, 0], "chocolate": [210, 105, 30], "coral": [255, 127, 80], "cornflowerblue": [100, 149, 237], "cornsilk": [255, 248, 220], "crimson": [220, 20, 60], "cyan": [0, 255, 255], "darkblue": [0, 0, 139], "darkcyan": [0, 139, 139], "darkgoldenrod": [184, 134, 11], "darkgray": [169, 169, 169], "darkgreen": [0, 100, 0], "darkgrey": [169, 169, 169], "darkkhaki": [189, 183, 107], "darkmagenta": [139, 0, 139], "darkolivegreen": [85, 107, 47], "darkorange": [255, 140, 0], "darkorchid": [153, 50, 204], "darkred": [139, 0, 0], "darksalmon": [233, 150, 122], "darkseagreen": [143, 188, 143], "darkslateblue": [72, 61, 139], "darkslategray": [47, 79, 79], "darkslategrey": [47, 79, 79], "darkturquoise": [0, 206, 209], "darkviolet": [148, 0, 211], "deeppink": [255, 20, 147], "deepskyblue": [0, 191, 255], "dimgray": [105, 105, 105], "dimgrey": [105, 105, 105], "dodgerblue": [30, 144, 255], "firebrick": [178, 34, 34], "floralwhite": [255, 250, 240], "forestgreen": [34, 139, 34], "fuchsia": [255, 0, 255], "gainsboro": [220, 220, 220], "ghostwhite": [248, 248, 255], "gold": [255, 215, 0], "goldenrod": [218, 165, 32], "gray": [128, 128, 128], "green": [0, 128, 0], "greenyellow": [173, 255, 47], "grey": [128, 128, 128], "honeydew": [240, 255, 240], "hotpink": [255, 105, 180], "indianred": [205, 92, 92], "indigo": [75, 0, 130], "ivory": [255, 255, 240], "khaki": [240, 230, 140], "lavender": [230, 230, 250], "lavenderblush": [255, 240, 245], "lawngreen": [124, 252, 0], "lemonchiffon": [255, 250, 205], "lightblue": [173, 216, 230], "lightcoral": [240, 128, 128], "lightcyan": [224, 255, 255], "lightgoldenrodyellow": [250, 250, 210], "lightgray": [211, 211, 211], "lightgreen": [144, 238, 144], "lightgrey": [211, 211, 211], "lightpink": [255, 182, 193], "lightsalmon": [255, 160, 122], "lightseagreen": [32, 178, 170], "lightskyblue": [135, 206, 250], "lightslategray": [119, 136, 153], "lightslategrey": [119, 136, 153], "lightsteelblue": [176, 196, 222], "lightyellow": [255, 255, 224], "lime": [0, 255, 0], "limegreen": [50, 205, 50], "linen": [250, 240, 230], "magenta": [255, 0, 255], "maroon": [128, 0, 0], "mediumaquamarine": [102, 205, 170], "mediumblue": [0, 0, 205], "mediumorchid": [186, 85, 211], "mediumpurple": [147, 112, 219], "mediumseagreen": [60, 179, 113], "mediumslateblue": [123, 104, 238], "mediumspringgreen": [0, 250, 154], "mediumturquoise": [72, 209, 204], "mediumvioletred": [199, 21, 133], "midnightblue": [25, 25, 112], "mintcream": [245, 255, 250], "mistyrose": [255, 228, 225], "moccasin": [255, 228, 181], "navajowhite": [255, 222, 173], "navy": [0, 0, 128], "oldlace": [253, 245, 230], "olive": [128, 128, 0], "olivedrab": [107, 142, 35], "orange": [255, 165, 0], "orangered": [255, 69, 0], "orchid": [218, 112, 214], "palegoldenrod": [238, 232, 170], "palegreen": [152, 251, 152], "paleturquoise": [175, 238, 238], "palevioletred": [219, 112, 147], "papayawhip": [255, 239, 213], "peachpuff": [255, 218, 185], "peru": [205, 133, 63], "pink": [255, 192, 203], "plum": [221, 160, 221], "powderblue": [176, 224, 230], "purple": [128, 0, 128], "rebeccapurple": [102, 51, 153], "red": [255, 0, 0], "rosybrown": [188, 143, 143], "royalblue": [65, 105, 225], "saddlebrown": [139, 69, 19], "salmon": [250, 128, 114], "sandybrown": [244, 164, 96], "seagreen": [46, 139, 87], "seashell": [255, 245, 238], "sienna": [160, 82, 45], "silver": [192, 192, 192], "skyblue": [135, 206, 235], "slateblue": [106, 90, 205], "slategray": [112, 128, 144], "slategrey": [112, 128, 144], "snow": [255, 250, 250], "springgreen": [0, 255, 127], "steelblue": [70, 130, 180], "tan": [210, 180, 140], "teal": [0, 128, 128], "thistle": [216, 191, 216], "tomato": [255, 99, 71], "turquoise": [64, 224, 208], "violet": [238, 130, 238], "wheat": [245, 222, 179], "white": [255, 255, 255], "whitesmoke": [245, 245, 245], "yellow": [255, 255, 0], "yellowgreen": [154, 205, 50] }; },{}],7:[function(require,module,exports){ /** * @namespace Chart */ var Chart = require(28)(); require(26)(Chart); require(42)(Chart); require(22)(Chart); require(31)(Chart); require(25)(Chart); require(21)(Chart); require(23)(Chart); require(24)(Chart); require(29)(Chart); require(33)(Chart); require(34)(Chart); require(32)(Chart); require(35)(Chart); require(30)(Chart); require(27)(Chart); require(36)(Chart); require(37)(Chart); require(38)(Chart); require(39)(Chart); require(40)(Chart); require(45)(Chart); require(43)(Chart); require(44)(Chart); require(46)(Chart); require(47)(Chart); require(48)(Chart); // Controllers must be loaded after elements // See Chart.core.datasetController.dataElementType require(15)(Chart); require(16)(Chart); require(17)(Chart); require(18)(Chart); require(19)(Chart); require(20)(Chart); require(8)(Chart); require(9)(Chart); require(10)(Chart); require(11)(Chart); require(12)(Chart); require(13)(Chart); require(14)(Chart); window.Chart = module.exports = Chart; },{"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,"42":42,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"8":8,"9":9}],8:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { Chart.Bar = function(context, config) { config.type = 'bar'; return new Chart(context, config); }; }; },{}],9:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { Chart.Bubble = function(context, config) { config.type = 'bubble'; return new Chart(context, config); }; }; },{}],10:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { Chart.Doughnut = function(context, config) { config.type = 'doughnut'; return new Chart(context, config); }; }; },{}],11:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { Chart.Line = function(context, config) { config.type = 'line'; return new Chart(context, config); }; }; },{}],12:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { Chart.PolarArea = function(context, config) { config.type = 'polarArea'; return new Chart(context, config); }; }; },{}],13:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { Chart.Radar = function(context, config) { config.type = 'radar'; return new Chart(context, config); }; }; },{}],14:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { var defaultConfig = { hover: { mode: 'single' }, scales: { xAxes: [{ type: 'linear', // scatter should not use a category axis position: 'bottom', id: 'x-axis-1' // need an ID so datasets can reference the scale }], yAxes: [{ type: 'linear', position: 'left', id: 'y-axis-1' }] }, tooltips: { callbacks: { title: function() { // Title doesn't make sense for scatter since we format the data as a point return ''; }, label: function(tooltipItem) { return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')'; } } } }; // Register the default config for this type Chart.defaults.scatter = defaultConfig; // Scatter charts use line controllers Chart.controllers.scatter = Chart.controllers.line; Chart.Scatter = function(context, config) { config.type = 'scatter'; return new Chart(context, config); }; }; },{}],15:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { var helpers = Chart.helpers; Chart.defaults.bar = { hover: { mode: 'label' }, scales: { xAxes: [{ type: 'category', // Specific to Bar Controller categoryPercentage: 0.8, barPercentage: 0.9, // grid line settings gridLines: { offsetGridLines: true } }], yAxes: [{ type: 'linear' }] } }; Chart.controllers.bar = Chart.DatasetController.extend({ dataElementType: Chart.elements.Rectangle, initialize: function(chart, datasetIndex) { Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex); var me = this; var meta = me.getMeta(); var dataset = me.getDataset(); meta.stack = dataset.stack; // Use this to indicate that this is a bar dataset. meta.bar = true; }, // Correctly calculate the bar width accounting for stacks and the fact that not all bars are visible getStackCount: function() { var me = this; var meta = me.getMeta(); var yScale = me.getScaleForId(meta.yAxisID); var stacks = []; helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) { var dsMeta = me.chart.getDatasetMeta(datasetIndex); if (dsMeta.bar && me.chart.isDatasetVisible(datasetIndex) && (yScale.options.stacked === false || (yScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) || (yScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) { stacks.push(dsMeta.stack); } }, me); return stacks.length; }, update: function(reset) { var me = this; helpers.each(me.getMeta().data, function(rectangle, index) { me.updateElement(rectangle, index, reset); }, me); }, updateElement: function(rectangle, index, reset) { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var yScale = me.getScaleForId(meta.yAxisID); var scaleBase = yScale.getBasePixel(); var rectangleElementOptions = me.chart.options.elements.rectangle; var custom = rectangle.custom || {}; var dataset = me.getDataset(); rectangle._xScale = xScale; rectangle._yScale = yScale; rectangle._datasetIndex = me.index; rectangle._index = index; var ruler = me.getRuler(index); // The index argument for compatible rectangle._model = { x: me.calculateBarX(index, me.index, ruler), y: reset ? scaleBase : me.calculateBarY(index, me.index), // Tooltip label: me.chart.data.labels[index], datasetLabel: dataset.label, // Appearance horizontal: false, base: reset ? scaleBase : me.calculateBarBase(me.index, index), width: me.calculateBarWidth(ruler), backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped, borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) }; rectangle.pivot(); }, calculateBarBase: function(datasetIndex, index) { var me = this; var meta = me.getMeta(); var yScale = me.getScaleForId(meta.yAxisID); var base = yScale.getBaseValue(); var original = base; if ((yScale.options.stacked === true) || (yScale.options.stacked === undefined && meta.stack !== undefined)) { var chart = me.chart; var datasets = chart.data.datasets; var value = Number(datasets[datasetIndex].data[index]); for (var i = 0; i < datasetIndex; i++) { var currentDs = datasets[i]; var currentDsMeta = chart.getDatasetMeta(i); if (currentDsMeta.bar && currentDsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i) && meta.stack === currentDsMeta.stack) { var currentVal = Number(currentDs.data[index]); base += value < 0 ? Math.min(currentVal, original) : Math.max(currentVal, original); } } return yScale.getPixelForValue(base); } return yScale.getBasePixel(); }, getRuler: function() { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var stackCount = me.getStackCount(); var tickWidth = xScale.width / xScale.ticks.length; var categoryWidth = tickWidth * xScale.options.categoryPercentage; var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2; var fullBarWidth = categoryWidth / stackCount; var barWidth = fullBarWidth * xScale.options.barPercentage; var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage); return { stackCount: stackCount, tickWidth: tickWidth, categoryWidth: categoryWidth, categorySpacing: categorySpacing, fullBarWidth: fullBarWidth, barWidth: barWidth, barSpacing: barSpacing }; }, calculateBarWidth: function(ruler) { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); if (xScale.options.barThickness) { return xScale.options.barThickness; } return ruler.barWidth; }, // Get stack index from the given dataset index accounting for stacks and the fact that not all bars are visible getStackIndex: function(datasetIndex) { var me = this; var meta = me.chart.getDatasetMeta(datasetIndex); var yScale = me.getScaleForId(meta.yAxisID); var dsMeta, j; var stacks = [meta.stack]; for (j = 0; j < datasetIndex; ++j) { dsMeta = this.chart.getDatasetMeta(j); if (dsMeta.bar && this.chart.isDatasetVisible(j) && (yScale.options.stacked === false || (yScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) || (yScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) { stacks.push(dsMeta.stack); } } return stacks.length - 1; }, calculateBarX: function(index, datasetIndex, ruler) { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var stackIndex = me.getStackIndex(datasetIndex); var leftTick = xScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo); leftTick -= me.chart.isCombo ? (ruler.tickWidth / 2) : 0; return leftTick + (ruler.barWidth / 2) + ruler.categorySpacing + (ruler.barWidth * stackIndex) + (ruler.barSpacing / 2) + (ruler.barSpacing * stackIndex); }, calculateBarY: function(index, datasetIndex) { var me = this; var meta = me.getMeta(); var yScale = me.getScaleForId(meta.yAxisID); var value = Number(me.getDataset().data[index]); if (yScale.options.stacked || (yScale.options.stacked === undefined && meta.stack !== undefined)) { var base = yScale.getBaseValue(); var sumPos = base, sumNeg = base; for (var i = 0; i < datasetIndex; i++) { var ds = me.chart.data.datasets[i]; var dsMeta = me.chart.getDatasetMeta(i); if (dsMeta.bar && dsMeta.yAxisID === yScale.id && me.chart.isDatasetVisible(i) && meta.stack === dsMeta.stack) { var stackedVal = Number(ds.data[index]); if (stackedVal < 0) { sumNeg += stackedVal || 0; } else { sumPos += stackedVal || 0; } } } if (value < 0) { return yScale.getPixelForValue(sumNeg + value); } return yScale.getPixelForValue(sumPos + value); } return yScale.getPixelForValue(value); }, draw: function(ease) { var me = this; var easingDecimal = ease || 1; var metaData = me.getMeta().data; var dataset = me.getDataset(); var i, len; Chart.canvasHelpers.clipArea(me.chart.chart.ctx, me.chart.chartArea); for (i = 0, len = metaData.length; i < len; ++i) { var d = dataset.data[i]; if (d !== null && d !== undefined && !isNaN(d)) { metaData[i].transition(easingDecimal).draw(); } } Chart.canvasHelpers.unclipArea(me.chart.chart.ctx); }, setHoverStyle: function(rectangle) { var dataset = this.chart.data.datasets[rectangle._datasetIndex]; var index = rectangle._index; var custom = rectangle.custom || {}; var model = rectangle._model; model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor)); model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth); }, removeHoverStyle: function(rectangle) { var dataset = this.chart.data.datasets[rectangle._datasetIndex]; var index = rectangle._index; var custom = rectangle.custom || {}; var model = rectangle._model; var rectangleElementOptions = this.chart.options.elements.rectangle; model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor); model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor); model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth); } }); // including horizontalBar in the bar file, instead of a file of its own // it extends bar (like pie extends doughnut) Chart.defaults.horizontalBar = { hover: { mode: 'label' }, scales: { xAxes: [{ type: 'linear', position: 'bottom' }], yAxes: [{ position: 'left', type: 'category', // Specific to Horizontal Bar Controller categoryPercentage: 0.8, barPercentage: 0.9, // grid line settings gridLines: { offsetGridLines: true } }] }, elements: { rectangle: { borderSkipped: 'left' } }, tooltips: { callbacks: { title: function(tooltipItems, data) { // Pick first xLabel for now var title = ''; if (tooltipItems.length > 0) { if (tooltipItems[0].yLabel) { title = tooltipItems[0].yLabel; } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) { title = data.labels[tooltipItems[0].index]; } } return title; }, label: function(tooltipItem, data) { var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || ''; return datasetLabel + ': ' + tooltipItem.xLabel; } } } }; Chart.controllers.horizontalBar = Chart.controllers.bar.extend({ // Correctly calculate the bar width accounting for stacks and the fact that not all bars are visible getStackCount: function() { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var stacks = []; helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) { var dsMeta = me.chart.getDatasetMeta(datasetIndex); if (dsMeta.bar && me.chart.isDatasetVisible(datasetIndex) && (xScale.options.stacked === false || (xScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) || (xScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) { stacks.push(dsMeta.stack); } }, me); return stacks.length; }, updateElement: function(rectangle, index, reset) { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var yScale = me.getScaleForId(meta.yAxisID); var scaleBase = xScale.getBasePixel(); var custom = rectangle.custom || {}; var dataset = me.getDataset(); var rectangleElementOptions = me.chart.options.elements.rectangle; rectangle._xScale = xScale; rectangle._yScale = yScale; rectangle._datasetIndex = me.index; rectangle._index = index; var ruler = me.getRuler(index); // The index argument for compatible rectangle._model = { x: reset ? scaleBase : me.calculateBarX(index, me.index), y: me.calculateBarY(index, me.index, ruler), // Tooltip label: me.chart.data.labels[index], datasetLabel: dataset.label, // Appearance horizontal: true, base: reset ? scaleBase : me.calculateBarBase(me.index, index), height: me.calculateBarHeight(ruler), backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped, borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) }; rectangle.pivot(); }, calculateBarBase: function(datasetIndex, index) { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var base = xScale.getBaseValue(); var originalBase = base; if (xScale.options.stacked || (xScale.options.stacked === undefined && meta.stack !== undefined)) { var chart = me.chart; var datasets = chart.data.datasets; var value = Number(datasets[datasetIndex].data[index]); for (var i = 0; i < datasetIndex; i++) { var currentDs = datasets[i]; var currentDsMeta = chart.getDatasetMeta(i); if (currentDsMeta.bar && currentDsMeta.xAxisID === xScale.id && chart.isDatasetVisible(i) && meta.stack === currentDsMeta.stack) { var currentVal = Number(currentDs.data[index]); base += value < 0 ? Math.min(currentVal, originalBase) : Math.max(currentVal, originalBase); } } return xScale.getPixelForValue(base); } return xScale.getBasePixel(); }, getRuler: function() { var me = this; var meta = me.getMeta(); var yScale = me.getScaleForId(meta.yAxisID); var stackCount = me.getStackCount(); var tickHeight = yScale.height / yScale.ticks.length; var categoryHeight = tickHeight * yScale.options.categoryPercentage; var categorySpacing = (tickHeight - (tickHeight * yScale.options.categoryPercentage)) / 2; var fullBarHeight = categoryHeight / stackCount; var barHeight = fullBarHeight * yScale.options.barPercentage; var barSpacing = fullBarHeight - (fullBarHeight * yScale.options.barPercentage); return { stackCount: stackCount, tickHeight: tickHeight, categoryHeight: categoryHeight, categorySpacing: categorySpacing, fullBarHeight: fullBarHeight, barHeight: barHeight, barSpacing: barSpacing }; }, calculateBarHeight: function(ruler) { var me = this; var meta = me.getMeta(); var yScale = me.getScaleForId(meta.yAxisID); if (yScale.options.barThickness) { return yScale.options.barThickness; } return ruler.barHeight; }, // Get stack index from the given dataset index accounting for stacks and the fact that not all bars are visible getStackIndex: function(datasetIndex) { var me = this; var meta = me.chart.getDatasetMeta(datasetIndex); var xScale = me.getScaleForId(meta.xAxisID); var dsMeta, j; var stacks = [meta.stack]; for (j = 0; j < datasetIndex; ++j) { dsMeta = this.chart.getDatasetMeta(j); if (dsMeta.bar && this.chart.isDatasetVisible(j) && (xScale.options.stacked === false || (xScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) || (xScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) { stacks.push(dsMeta.stack); } } return stacks.length - 1; }, calculateBarX: function(index, datasetIndex) { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var value = Number(me.getDataset().data[index]); if (xScale.options.stacked || (xScale.options.stacked === undefined && meta.stack !== undefined)) { var base = xScale.getBaseValue(); var sumPos = base, sumNeg = base; for (var i = 0; i < datasetIndex; i++) { var ds = me.chart.data.datasets[i]; var dsMeta = me.chart.getDatasetMeta(i); if (dsMeta.bar && dsMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(i) && meta.stack === dsMeta.stack) { var stackedVal = Number(ds.data[index]); if (stackedVal < 0) { sumNeg += stackedVal || 0; } else { sumPos += stackedVal || 0; } } } if (value < 0) { return xScale.getPixelForValue(sumNeg + value); } return xScale.getPixelForValue(sumPos + value); } return xScale.getPixelForValue(value); }, calculateBarY: function(index, datasetIndex, ruler) { var me = this; var meta = me.getMeta(); var yScale = me.getScaleForId(meta.yAxisID); var stackIndex = me.getStackIndex(datasetIndex); var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo); topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0; return topTick + (ruler.barHeight / 2) + ruler.categorySpacing + (ruler.barHeight * stackIndex) + (ruler.barSpacing / 2) + (ruler.barSpacing * stackIndex); } }); }; },{}],16:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { var helpers = Chart.helpers; Chart.defaults.bubble = { hover: { mode: 'single' }, scales: { xAxes: [{ type: 'linear', // bubble should probably use a linear scale by default position: 'bottom', id: 'x-axis-0' // need an ID so datasets can reference the scale }], yAxes: [{ type: 'linear', position: 'left', id: 'y-axis-0' }] }, tooltips: { callbacks: { title: function() { // Title doesn't make sense for scatter since we format the data as a point return ''; }, label: function(tooltipItem, data) { var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || ''; var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; return datasetLabel + ': (' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ', ' + dataPoint.r + ')'; } } } }; Chart.controllers.bubble = Chart.DatasetController.extend({ dataElementType: Chart.elements.Point, update: function(reset) { var me = this; var meta = me.getMeta(); var points = meta.data; // Update Points helpers.each(points, function(point, index) { me.updateElement(point, index, reset); }); }, updateElement: function(point, index, reset) { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var yScale = me.getScaleForId(meta.yAxisID); var custom = point.custom || {}; var dataset = me.getDataset(); var data = dataset.data[index]; var pointElementOptions = me.chart.options.elements.point; var dsIndex = me.index; helpers.extend(point, { // Utility _xScale: xScale, _yScale: yScale, _datasetIndex: dsIndex, _index: index, // Desired view properties _model: { x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex, me.chart.isCombo), y: reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex), // Appearance radius: reset ? 0 : custom.radius ? custom.radius : me.getRadius(data), // Tooltip hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius) } }); // Trick to reset the styles of the point Chart.DatasetController.prototype.removeHoverStyle.call(me, point, pointElementOptions); var model = point._model; model.skip = custom.skip ? custom.skip : (isNaN(model.x) || isNaN(model.y)); point.pivot(); }, getRadius: function(value) { return value.r || this.chart.options.elements.point.radius; }, setHoverStyle: function(point) { var me = this; Chart.DatasetController.prototype.setHoverStyle.call(me, point); // Radius var dataset = me.chart.data.datasets[point._datasetIndex]; var index = point._index; var custom = point.custom || {}; var model = point._model; model.radius = custom.hoverRadius ? custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, me.chart.options.elements.point.hoverRadius)) + me.getRadius(dataset.data[index]); }, removeHoverStyle: function(point) { var me = this; Chart.DatasetController.prototype.removeHoverStyle.call(me, point, me.chart.options.elements.point); var dataVal = me.chart.data.datasets[point._datasetIndex].data[point._index]; var custom = point.custom || {}; var model = point._model; model.radius = custom.radius ? custom.radius : me.getRadius(dataVal); } }); }; },{}],17:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { var helpers = Chart.helpers, defaults = Chart.defaults; defaults.doughnut = { animation: { // Boolean - Whether we animate the rotation of the Doughnut animateRotate: true, // Boolean - Whether we animate scaling the Doughnut from the centre animateScale: false }, aspectRatio: 1, hover: { mode: 'single' }, legendCallback: function(chart) { var text = []; text.push(''); return text.join(''); }, legend: { labels: { generateLabels: function(chart) { var data = chart.data; if (data.labels.length && data.datasets.length) { return data.labels.map(function(label, i) { var meta = chart.getDatasetMeta(0); var ds = data.datasets[0]; var arc = meta.data[i]; var custom = arc && arc.custom || {}; var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; var arcOpts = chart.options.elements.arc; var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); return { text: label, fillStyle: fill, strokeStyle: stroke, lineWidth: bw, hidden: isNaN(ds.data[i]) || meta.data[i].hidden, // Extra data used for toggling the correct item index: i }; }); } return []; } }, onClick: function(e, legendItem) { var index = legendItem.index; var chart = this.chart; var i, ilen, meta; for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { meta = chart.getDatasetMeta(i); // toggle visibility of index if exists if (meta.data[index]) { meta.data[index].hidden = !meta.data[index].hidden; } } chart.update(); } }, // The percentage of the chart that we cut out of the middle. cutoutPercentage: 50, // The rotation of the chart, where the first data arc begins. rotation: Math.PI * -0.5, // The total circumference of the chart. circumference: Math.PI * 2.0, // Need to override these to give a nice default tooltips: { callbacks: { title: function() { return ''; }, label: function(tooltipItem, data) { var dataLabel = data.labels[tooltipItem.index]; var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; if (helpers.isArray(dataLabel)) { // show value on first line of multiline label // need to clone because we are changing the value dataLabel = dataLabel.slice(); dataLabel[0] += value; } else { dataLabel += value; } return dataLabel; } } } }; defaults.pie = helpers.clone(defaults.doughnut); helpers.extend(defaults.pie, { cutoutPercentage: 0 }); Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({ dataElementType: Chart.elements.Arc, linkScales: helpers.noop, // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly getRingIndex: function(datasetIndex) { var ringIndex = 0; for (var j = 0; j < datasetIndex; ++j) { if (this.chart.isDatasetVisible(j)) { ++ringIndex; } } return ringIndex; }, update: function(reset) { var me = this; var chart = me.chart, chartArea = chart.chartArea, opts = chart.options, arcOpts = opts.elements.arc, availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth, availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth, minSize = Math.min(availableWidth, availableHeight), offset = { x: 0, y: 0 }, meta = me.getMeta(), cutoutPercentage = opts.cutoutPercentage, circumference = opts.circumference; // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc if (circumference < Math.PI * 2.0) { var startAngle = opts.rotation % (Math.PI * 2.0); startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0); var endAngle = startAngle + circumference; var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)}; var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)}; var contains0 = (startAngle <= 0 && 0 <= endAngle) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle); var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle); var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle); var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle); var cutout = cutoutPercentage / 100.0; 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))}; 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))}; var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5}; minSize = Math.min(availableWidth / size.width, availableHeight / size.height); offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5}; } chart.borderWidth = me.getMaxBorderWidth(meta.data); chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0); chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0); chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); chart.offsetX = offset.x * chart.outerRadius; chart.offsetY = offset.y * chart.outerRadius; meta.total = me.calculateTotal(); me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index)); me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0); helpers.each(meta.data, function(arc, index) { me.updateElement(arc, index, reset); }); }, updateElement: function(arc, index, reset) { var me = this; var chart = me.chart, chartArea = chart.chartArea, opts = chart.options, animationOpts = opts.animation, centerX = (chartArea.left + chartArea.right) / 2, centerY = (chartArea.top + chartArea.bottom) / 2, startAngle = opts.rotation, // non reset case handled later endAngle = opts.rotation, // non reset case handled later dataset = me.getDataset(), circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)), innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius, outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius, valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; helpers.extend(arc, { // Utility _datasetIndex: me.index, _index: index, // Desired view properties _model: { x: centerX + chart.offsetX, y: centerY + chart.offsetY, startAngle: startAngle, endAngle: endAngle, circumference: circumference, outerRadius: outerRadius, innerRadius: innerRadius, label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index]) } }); var model = arc._model; // Resets the visual styles this.removeHoverStyle(arc); // Set correct angles if not resetting if (!reset || !animationOpts.animateRotate) { if (index === 0) { model.startAngle = opts.rotation; } else { model.startAngle = me.getMeta().data[index - 1]._model.endAngle; } model.endAngle = model.startAngle + model.circumference; } arc.pivot(); }, removeHoverStyle: function(arc) { Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); }, calculateTotal: function() { var dataset = this.getDataset(); var meta = this.getMeta(); var total = 0; var value; helpers.each(meta.data, function(element, index) { value = dataset.data[index]; if (!isNaN(value) && !element.hidden) { total += Math.abs(value); } }); /* if (total === 0) { total = NaN; }*/ return total; }, calculateCircumference: function(value) { var total = this.getMeta().total; if (total > 0 && !isNaN(value)) { return (Math.PI * 2.0) * (value / total); } return 0; }, // gets the max border or hover width to properly scale pie charts getMaxBorderWidth: function(elements) { var max = 0, index = this.index, length = elements.length, borderWidth, hoverWidth; for (var i = 0; i < length; i++) { borderWidth = elements[i]._model ? elements[i]._model.borderWidth : 0; hoverWidth = elements[i]._chart ? elements[i]._chart.config.data.datasets[index].hoverBorderWidth : 0; max = borderWidth > max ? borderWidth : max; max = hoverWidth > max ? hoverWidth : max; } return max; } }); }; },{}],18:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { var helpers = Chart.helpers; Chart.defaults.line = { showLines: true, spanGaps: false, hover: { mode: 'label' }, scales: { xAxes: [{ type: 'category', id: 'x-axis-0' }], yAxes: [{ type: 'linear', id: 'y-axis-0' }] } }; function lineEnabled(dataset, options) { return helpers.getValueOrDefault(dataset.showLine, options.showLines); } Chart.controllers.line = Chart.DatasetController.extend({ datasetElementType: Chart.elements.Line, dataElementType: Chart.elements.Point, update: function(reset) { var me = this; var meta = me.getMeta(); var line = meta.dataset; var points = meta.data || []; var options = me.chart.options; var lineElementOptions = options.elements.line; var scale = me.getScaleForId(meta.yAxisID); var i, ilen, custom; var dataset = me.getDataset(); var showLine = lineEnabled(dataset, options); // Update Line if (showLine) { custom = line.custom || {}; // Compatibility: If the properties are defined with only the old name, use those values if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) { dataset.lineTension = dataset.tension; } // Utility line._scale = scale; line._datasetIndex = me.index; // Data line._children = points; // Model line._model = { // Appearance // The default behavior of lines is to break at null values, according // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158 // This option gives lines the ability to span gaps spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps, tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension), backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor), borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth), borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor), borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle), borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash), borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset), borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle), fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill), steppedLine: custom.steppedLine ? custom.steppedLine : helpers.getValueOrDefault(dataset.steppedLine, lineElementOptions.stepped), cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.getValueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode), // Scale scaleTop: scale.top, scaleBottom: scale.bottom, scaleZero: scale.getBasePixel() }; line.pivot(); } // Update Points for (i=0, ilen=points.length; i'); var data = chart.data; var datasets = data.datasets; var labels = data.labels; if (datasets.length) { for (var i = 0; i < datasets[0].data.length; ++i) { text.push('
  • '); if (labels[i]) { text.push(labels[i]); } text.push('
  • '); } } text.push(''); return text.join(''); }, legend: { labels: { generateLabels: function(chart) { var data = chart.data; if (data.labels.length && data.datasets.length) { return data.labels.map(function(label, i) { var meta = chart.getDatasetMeta(0); var ds = data.datasets[0]; var arc = meta.data[i]; var custom = arc.custom || {}; var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; var arcOpts = chart.options.elements.arc; var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); return { text: label, fillStyle: fill, strokeStyle: stroke, lineWidth: bw, hidden: isNaN(ds.data[i]) || meta.data[i].hidden, // Extra data used for toggling the correct item index: i }; }); } return []; } }, onClick: function(e, legendItem) { var index = legendItem.index; var chart = this.chart; var i, ilen, meta; for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { meta = chart.getDatasetMeta(i); meta.data[index].hidden = !meta.data[index].hidden; } chart.update(); } }, // Need to override these to give a nice default tooltips: { callbacks: { title: function() { return ''; }, label: function(tooltipItem, data) { return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel; } } } }; Chart.controllers.polarArea = Chart.DatasetController.extend({ dataElementType: Chart.elements.Arc, linkScales: helpers.noop, update: function(reset) { var me = this; var chart = me.chart; var chartArea = chart.chartArea; var meta = me.getMeta(); var opts = chart.options; var arcOpts = opts.elements.arc; var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0); chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index); me.innerRadius = me.outerRadius - chart.radiusLength; meta.count = me.countVisibleElements(); helpers.each(meta.data, function(arc, index) { me.updateElement(arc, index, reset); }); }, updateElement: function(arc, index, reset) { var me = this; var chart = me.chart; var dataset = me.getDataset(); var opts = chart.options; var animationOpts = opts.animation; var scale = chart.scale; var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; var labels = chart.data.labels; var circumference = me.calculateCircumference(dataset.data[index]); var centerX = scale.xCenter; var centerY = scale.yCenter; // If there is NaN data before us, we need to calculate the starting angle correctly. // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data var visibleCount = 0; var meta = me.getMeta(); for (var i = 0; i < index; ++i) { if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) { ++visibleCount; } } // var negHalfPI = -0.5 * Math.PI; var datasetStartAngle = opts.startAngle; var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); var startAngle = datasetStartAngle + (circumference * visibleCount); var endAngle = startAngle + (arc.hidden ? 0 : circumference); var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); helpers.extend(arc, { // Utility _datasetIndex: me.index, _index: index, _scale: scale, // Desired view properties _model: { x: centerX, y: centerY, innerRadius: 0, outerRadius: reset ? resetRadius : distance, startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle, endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle, label: getValueAtIndexOrDefault(labels, index, labels[index]) } }); // Apply border and fill style me.removeHoverStyle(arc); arc.pivot(); }, removeHoverStyle: function(arc) { Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); }, countVisibleElements: function() { var dataset = this.getDataset(); var meta = this.getMeta(); var count = 0; helpers.each(meta.data, function(element, index) { if (!isNaN(dataset.data[index]) && !element.hidden) { count++; } }); return count; }, calculateCircumference: function(value) { var count = this.getMeta().count; if (count > 0 && !isNaN(value)) { return (2 * Math.PI) / count; } return 0; } }); }; },{}],20:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { var helpers = Chart.helpers; Chart.defaults.radar = { aspectRatio: 1, scale: { type: 'radialLinear' }, elements: { line: { tension: 0 // no bezier in radar } } }; Chart.controllers.radar = Chart.DatasetController.extend({ datasetElementType: Chart.elements.Line, dataElementType: Chart.elements.Point, linkScales: helpers.noop, update: function(reset) { var me = this; var meta = me.getMeta(); var line = meta.dataset; var points = meta.data; var custom = line.custom || {}; var dataset = me.getDataset(); var lineElementOptions = me.chart.options.elements.line; var scale = me.chart.scale; // Compatibility: If the properties are defined with only the old name, use those values if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) { dataset.lineTension = dataset.tension; } helpers.extend(meta.dataset, { // Utility _datasetIndex: me.index, // Data _children: points, _loop: true, // Model _model: { // Appearance tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension), backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor), borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth), borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor), fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill), borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle), borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash), borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset), borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle), // Scale scaleTop: scale.top, scaleBottom: scale.bottom, scaleZero: scale.getBasePosition() } }); meta.dataset.pivot(); // Update Points helpers.each(points, function(point, index) { me.updateElement(point, index, reset); }, me); // Update bezier control points me.updateBezierControlPoints(); }, updateElement: function(point, index, reset) { var me = this; var custom = point.custom || {}; var dataset = me.getDataset(); var scale = me.chart.scale; var pointElementOptions = me.chart.options.elements.point; var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]); helpers.extend(point, { // Utility _datasetIndex: me.index, _index: index, _scale: scale, // Desired view properties _model: { x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales y: reset ? scale.yCenter : pointPosition.y, // Appearance tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension), radius: custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius), backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor), borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor), borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth), pointStyle: custom.pointStyle ? custom.pointStyle : helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle), // Tooltip hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius) } }); point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); }, updateBezierControlPoints: function() { var chartArea = this.chart.chartArea; var meta = this.getMeta(); helpers.each(meta.data, function(point, index) { var model = point._model; var controlPoints = helpers.splineCurve( helpers.previousItem(meta.data, index, true)._model, model, helpers.nextItem(meta.data, index, true)._model, model.tension ); // Prevent the bezier going outside of the bounds of the graph model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left); model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top); model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left); model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top); // Now pivot the point for animation point.pivot(); }); }, draw: function(ease) { var meta = this.getMeta(); var easingDecimal = ease || 1; // Transition Point Locations helpers.each(meta.data, function(point) { point.transition(easingDecimal); }); // Transition and Draw the line meta.dataset.transition(easingDecimal).draw(); // Draw the points helpers.each(meta.data, function(point) { point.draw(); }); }, setHoverStyle: function(point) { // Point var dataset = this.chart.data.datasets[point._datasetIndex]; var custom = point.custom || {}; var index = point._index; var model = point._model; model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius); model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor)); model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth); }, removeHoverStyle: function(point) { var dataset = this.chart.data.datasets[point._datasetIndex]; var custom = point.custom || {}; var index = point._index; var model = point._model; var pointElementOptions = this.chart.options.elements.point; model.radius = custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.radius, index, pointElementOptions.radius); model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor); model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor); model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth); } }); }; },{}],21:[function(require,module,exports){ /* global window: false */ 'use strict'; module.exports = function(Chart) { var helpers = Chart.helpers; Chart.defaults.global.animation = { duration: 1000, easing: 'easeOutQuart', onProgress: helpers.noop, onComplete: helpers.noop }; Chart.Animation = Chart.Element.extend({ currentStep: null, // the current animation step numSteps: 60, // default number of steps easing: '', // the easing to use for this animation render: null, // render function used by the animation service onAnimationProgress: null, // user specified callback to fire on each step of the animation onAnimationComplete: null // user specified callback to fire when the animation finishes }); Chart.animationService = { frameDuration: 17, animations: [], dropFrames: 0, request: null, /** * @function Chart.animationService.addAnimation * @param chartInstance {ChartController} the chart to animate * @param animationObject {IAnimation} the animation that we will animate * @param duration {Number} length of animation in ms * @param lazy {Boolean} if true, the chart is not marked as animating to enable more responsive interactions */ addAnimation: function(chartInstance, animationObject, duration, lazy) { var me = this; if (!lazy) { chartInstance.animating = true; } for (var index = 0; index < me.animations.length; ++index) { if (me.animations[index].chartInstance === chartInstance) { // replacing an in progress animation me.animations[index].animationObject = animationObject; return; } } me.animations.push({ chartInstance: chartInstance, animationObject: animationObject }); // If there are no animations queued, manually kickstart a digest, for lack of a better word if (me.animations.length === 1) { me.requestAnimationFrame(); } }, // Cancel the animation for a given chart instance cancelAnimation: function(chartInstance) { var index = helpers.findIndex(this.animations, function(animationWrapper) { return animationWrapper.chartInstance === chartInstance; }); if (index !== -1) { this.animations.splice(index, 1); chartInstance.animating = false; } }, requestAnimationFrame: function() { var me = this; if (me.request === null) { // Skip animation frame requests until the active one is executed. // This can happen when processing mouse events, e.g. 'mousemove' // and 'mouseout' events will trigger multiple renders. me.request = helpers.requestAnimFrame.call(window, function() { me.request = null; me.startDigest(); }); } }, startDigest: function() { var me = this; var startTime = Date.now(); var framesToDrop = 0; if (me.dropFrames > 1) { framesToDrop = Math.floor(me.dropFrames); me.dropFrames = me.dropFrames % 1; } var i = 0; while (i < me.animations.length) { if (me.animations[i].animationObject.currentStep === null) { me.animations[i].animationObject.currentStep = 0; } me.animations[i].animationObject.currentStep += 1 + framesToDrop; if (me.animations[i].animationObject.currentStep > me.animations[i].animationObject.numSteps) { me.animations[i].animationObject.currentStep = me.animations[i].animationObject.numSteps; } me.animations[i].animationObject.render(me.animations[i].chartInstance, me.animations[i].animationObject); if (me.animations[i].animationObject.onAnimationProgress && me.animations[i].animationObject.onAnimationProgress.call) { me.animations[i].animationObject.onAnimationProgress.call(me.animations[i].chartInstance, me.animations[i]); } if (me.animations[i].animationObject.currentStep === me.animations[i].animationObject.numSteps) { if (me.animations[i].animationObject.onAnimationComplete && me.animations[i].animationObject.onAnimationComplete.call) { me.animations[i].animationObject.onAnimationComplete.call(me.animations[i].chartInstance, me.animations[i]); } // executed the last frame. Remove the animation. me.animations[i].chartInstance.animating = false; me.animations.splice(i, 1); } else { ++i; } } var endTime = Date.now(); var dropFrames = (endTime - startTime) / me.frameDuration; me.dropFrames += dropFrames; // Do we have more stuff to animate? if (me.animations.length > 0) { me.requestAnimationFrame(); } } }; }; },{}],22:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { // Global Chart canvas helpers object for drawing items to canvas var helpers = Chart.canvasHelpers = {}; helpers.drawPoint = function(ctx, pointStyle, radius, x, y) { var type, edgeLength, xOffset, yOffset, height, size; if (typeof pointStyle === 'object') { type = pointStyle.toString(); if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2); return; } } if (isNaN(radius) || radius <= 0) { return; } switch (pointStyle) { // Default includes circle default: ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2); ctx.closePath(); ctx.fill(); break; case 'triangle': ctx.beginPath(); edgeLength = 3 * radius / Math.sqrt(3); height = edgeLength * Math.sqrt(3) / 2; ctx.moveTo(x - edgeLength / 2, y + height / 3); ctx.lineTo(x + edgeLength / 2, y + height / 3); ctx.lineTo(x, y - 2 * height / 3); ctx.closePath(); ctx.fill(); break; case 'rect': size = 1 / Math.SQRT2 * radius; ctx.beginPath(); ctx.fillRect(x - size, y - size, 2 * size, 2 * size); ctx.strokeRect(x - size, y - size, 2 * size, 2 * size); break; case 'rectRounded': var offset = radius / Math.SQRT2; var leftX = x - offset; var topY = y - offset; var sideSize = Math.SQRT2 * radius; Chart.helpers.drawRoundedRectangle(ctx, leftX, topY, sideSize, sideSize, radius / 2); ctx.fill(); break; case 'rectRot': size = 1 / Math.SQRT2 * radius; ctx.beginPath(); ctx.moveTo(x - size, y); ctx.lineTo(x, y + size); ctx.lineTo(x + size, y); ctx.lineTo(x, y - size); ctx.closePath(); ctx.fill(); break; case 'cross': ctx.beginPath(); ctx.moveTo(x, y + radius); ctx.lineTo(x, y - radius); ctx.moveTo(x - radius, y); ctx.lineTo(x + radius, y); ctx.closePath(); break; case 'crossRot': ctx.beginPath(); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; ctx.moveTo(x - xOffset, y - yOffset); ctx.lineTo(x + xOffset, y + yOffset); ctx.moveTo(x - xOffset, y + yOffset); ctx.lineTo(x + xOffset, y - yOffset); ctx.closePath(); break; case 'star': ctx.beginPath(); ctx.moveTo(x, y + radius); ctx.lineTo(x, y - radius); ctx.moveTo(x - radius, y); ctx.lineTo(x + radius, y); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; ctx.moveTo(x - xOffset, y - yOffset); ctx.lineTo(x + xOffset, y + yOffset); ctx.moveTo(x - xOffset, y + yOffset); ctx.lineTo(x + xOffset, y - yOffset); ctx.closePath(); break; case 'line': ctx.beginPath(); ctx.moveTo(x - radius, y); ctx.lineTo(x + radius, y); ctx.closePath(); break; case 'dash': ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x + radius, y); ctx.closePath(); break; } ctx.stroke(); }; helpers.clipArea = function(ctx, clipArea) { ctx.save(); ctx.beginPath(); ctx.rect(clipArea.left, clipArea.top, clipArea.right - clipArea.left, clipArea.bottom - clipArea.top); ctx.clip(); }; helpers.unclipArea = function(ctx) { ctx.restore(); }; }; },{}],23:[function(require,module,exports){ 'use strict'; module.exports = function(Chart) { var helpers = Chart.helpers; var plugins = Chart.plugins; var platform = Chart.platform; // Create a dictionary of chart types, to allow for extension of existing types Chart.types = {}; // Store a reference to each instance - allowing us to globally resize chart instances on window resize. // Destroy method on the chart will remove the instance of the chart from this reference. Chart.instances = {}; // Controllers available for dataset visualization eg. bar, line, slice, etc. Chart.controllers = {}; /** * Initializes the given config with global and chart default values. */ function initConfig(config) { config = config || {}; // Do NOT use configMerge() for the data object because this method merges arrays // and so would change references to labels and datasets, preventing data updates. var data = config.data = config.data || {}; data.datasets = data.datasets || []; data.labels = data.labels || []; config.options = helpers.configMerge( Chart.defaults.global, Chart.defaults[config.type], config.options || {}); return config; } /** * Updates the config of the chart * @param chart {Chart.Controller} chart to update the options for */ function updateConfig(chart) { var newOptions = chart.options; // Update Scale(s) with options if (newOptions.scale) { chart.scale.options = newOptions.scale; } else if (newOptions.scales) { newOptions.scales.xAxes.concat(newOptions.scales.yAxes).forEach(function(scaleOptions) { chart.scales[scaleOptions.id].options = scaleOptions; }); } // Tooltip chart.tooltip._options = newOptions.tooltips; } /** * @class Chart.Controller * The main controller of a chart. */ Chart.Controller = function(item, config, instance) { var me = this; config = initConfig(config); var context = platform.acquireContext(item, config); var canvas = context && context.canvas; var height = canvas && canvas.height; var width = canvas && canvas.width; instance.ctx = context; instance.canvas = canvas; instance.config = config; instance.width = width; instance.height = height; instance.aspectRatio = height? width / height : null; me.id = helpers.uid(); me.chart = instance; me.config = config; me.options = config.options; me._bufferedRender = false; // Add the chart instance to the global namespace Chart.instances[me.id] = me; Object.defineProperty(me, 'data', { get: function() { return me.config.data; } }); if (!context || !canvas) { // The given item is not a compatible context2d element, let's return before finalizing // the chart initialization but after setting basic chart / controller properties that // can help to figure out that the chart is not valid (e.g chart.canvas !== null); // https://github.com/chartjs/Chart.js/issues/2807 console.error("Failed to create chart: can't acquire context from the given item"); return me; } me.initialize(); me.update(); return me; }; helpers.extend(Chart.Controller.prototype, /** @lends Chart.Controller.prototype */ { initialize: function() { var me = this; // Before init plugin notification plugins.notify(me, 'beforeInit'); helpers.retinaScale(me.chart); me.bindEvents(); if (me.options.responsive) { // Initial resize before chart draws (must be silent to preserve initial animations). me.resize(true); } // Make sure scales have IDs and are built before we build any controllers. me.ensureScalesHaveIDs(); me.buildScales(); me.initToolTip(); // After init plugin notification plugins.notify(me, 'afterInit'); return me; }, clear: function() { helpers.clear(this.chart); return this; }, stop: function() { // Stops any current animation loop occurring Chart.animationService.cancelAnimation(this); return this; }, resize: function(silent) { var me = this; var chart = me.chart; var options = me.options; var canvas = chart.canvas; var aspectRatio = (options.maintainAspectRatio && chart.aspectRatio) || null; // the canvas render width and height will be casted to integers so make sure that // the canvas display style uses the same integer values to avoid blurring effect. var newWidth = Math.floor(helpers.getMaximumWidth(canvas)); var newHeight = Math.floor(aspectRatio? newWidth / aspectRatio : helpers.getMaximumHeight(canvas)); if (chart.width === newWidth && chart.height === newHeight) { return; } canvas.width = chart.width = newWidth; canvas.height = chart.height = newHeight; canvas.style.width = newWidth + 'px'; canvas.style.height = newHeight + 'px'; helpers.retinaScale(chart); if (!silent) { // Notify any plugins about the resize var newSize = {width: newWidth, height: newHeight}; plugins.notify(me, 'resize', [newSize]); // Notify of resize if (me.options.onResize) { me.options.onResize(me, newSize); } me.stop(); me.update(me.options.responsiveAnimationDuration); } }, ensureScalesHaveIDs: function() { var options = this.options; var scalesOptions = options.scales || {}; var scaleOptions = options.scale; helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) { xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index); }); helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) { yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index); }); if (scaleOptions) { scaleOptions.id = scaleOptions.id || 'scale'; } }, /** * Builds a map of scale ID to scale object for future lookup. */ buildScales: function() { var me = this; var options = me.options; var scales = me.scales = {}; var items = []; if (options.scales) { items = items.concat( (options.scales.xAxes || []).map(function(xAxisOptions) { return {options: xAxisOptions, dtype: 'category'}; }), (options.scales.yAxes || []).map(function(yAxisOptions) { return {options: yAxisOptions, dtype: 'linear'}; }) ); } if (options.scale) { items.push({options: options.scale, dtype: 'radialLinear', isDefault: true}); } helpers.each(items, function(item) { var scaleOptions = item.options; var scaleType = helpers.getValueOrDefault(scaleOptions.type, item.dtype); var scaleClass = Chart.scaleService.getScaleConstructor(scaleType); if (!scaleClass) { return; } var scale = new scaleClass({ id: scaleOptions.id, options: scaleOptions, ctx: me.chart.ctx, chart: me }); scales[scale.id] = scale; // TODO(SB): I think we should be able to remove this custom case (options.scale) // and consider it as a regular scale part of the "scales"" map only! This would // make the logic easier and remove some useless? custom code. if (item.isDefault) { me.scale = scale; } }); Chart.scaleService.addScalesToLayout(this); }, buildOrUpdateControllers: function() { var me = this; var types = []; var newControllers = []; helpers.each(me.data.datasets, function(dataset, datasetIndex) { var meta = me.getDatasetMeta(datasetIndex); if (!meta.type) { meta.type = dataset.type || me.config.type; } types.push(meta.type); if (meta.controller) { meta.controller.updateIndex(datasetIndex); } else { meta.controller = new Chart.controllers[meta.type](me, datasetIndex); newControllers.push(meta.controller); } }, me); if (types.length > 1) { for (var i = 1; i < types.length; i++) { if (types[i] !== types[i - 1]) { me.isCombo = true; break; } } } return newControllers; }, /** * Reset the elements of all datasets * @private */ resetElements: function() { var me = this; helpers.each(me.data.datasets, function(dataset, datasetIndex) { me.getDatasetMeta(datasetIndex).controller.reset(); }, me); }, /** * Resets the chart back to it's state before the initial animation */ reset: function() { this.resetElements(); this.tooltip.initialize(); }, update: function(animationDuration, lazy) { var me = this; updateConfig(me); if (plugins.notify(me, 'beforeUpdate') === false) { return; } // In case the entire data object changed me.tooltip._data = me.data; // Make sure dataset controllers are updated and new controllers are reset var newControllers = me.buildOrUpdateControllers(); // Make sure all dataset controllers have correct meta data counts helpers.each(me.data.datasets, function(dataset, datasetIndex) { me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements(); }, me); me.updateLayout(); // Can only reset the new controllers after the scales have been updated helpers.each(newControllers, function(controller) { controller.reset(); }); me.updateDatasets(); // Do this before render so that any plugins that need final scale updates can use it plugins.notify(me, 'afterUpdate'); if (me._bufferedRender) { me._bufferedRequest = { lazy: lazy, duration: animationDuration }; } else { me.render(animationDuration, lazy); } }, /** * Updates the chart layout unless a plugin returns `false` to the `beforeLayout` * hook, in which case, plugins will not be called on `afterLayout`. * @private */ updateLayout: function() { var me = this; if (plugins.notify(me, 'beforeLayout') === false) { return; } Chart.layoutService.update(this, this.chart.width, this.chart.height); /** * Provided for backward compatibility, use `afterLayout` instead. * @method IPlugin#afterScaleUpdate * @deprecated since version 2.5.0 * @todo remove at version 3 */ plugins.notify(me, 'afterScaleUpdate'); plugins.notify(me, 'afterLayout'); }, /** * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate` * hook, in which case, plugins will not be called on `afterDatasetsUpdate`. * @private */ updateDatasets: function() { var me = this; if (plugins.notify(me, 'beforeDatasetsUpdate') === false) { return; } for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { me.getDatasetMeta(i).controller.update(); } plugins.notify(me, 'afterDatasetsUpdate'); }, render: function(duration, lazy) { var me = this; if (plugins.notify(me, 'beforeRender') === false) { return; } var animationOptions = me.options.animation; var onComplete = function() { plugins.notify(me, 'afterRender'); var callback = animationOptions && animationOptions.onComplete; if (callback && callback.call) { callback.call(me); } }; if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) { var animation = new Chart.Animation(); animation.numSteps = (duration || animationOptions.duration) / 16.66; // 60 fps animation.easing = animationOptions.easing; // render function animation.render = function(chartInstance, animationObject) { var easingFunction = helpers.easingEffects[animationObject.easing]; var stepDecimal = animationObject.currentStep / animationObject.numSteps; var easeDecimal = easingFunction(stepDecimal); chartInstance.draw(easeDecimal, stepDecimal, animationObject.currentStep); }; // user events animation.onAnimationProgress = animationOptions.onProgress; animation.onAnimationComplete = onComplete; Chart.animationService.addAnimation(me, animation, duration, lazy); } else { me.draw(); onComplete(); } return me; }, draw: function(easingValue) { var me = this; me.clear(); if (easingValue === undefined || easingValue === null) { easingValue = 1; } if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) { return; } // Draw all the scales helpers.each(me.boxes, function(box) { box.draw(me.chartArea); }, me); if (me.scale) { me.scale.draw(); } me.drawDatasets(easingValue); // Finally draw the tooltip me.tooltip.transition(easingValue).draw(); plugins.notify(me, 'afterDraw', [easingValue]); }, /** * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw` * hook, in which case, plugins will not be called on `afterDatasetsDraw`. * @private */ drawDatasets: function(easingValue) { var me = this; if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) { return; } // Draw each dataset via its respective controller (reversed to support proper line stacking) helpers.each(me.data.datasets, function(dataset, datasetIndex) { if (me.isDatasetVisible(datasetIndex)) { me.getDatasetMeta(datasetIndex).controller.draw(easingValue); } }, me, true); plugins.notify(me, 'afterDatasetsDraw', [easingValue]); }, // Get the single element that was clicked on // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw getElementAtEvent: function(e) { return Chart.Interaction.modes.single(this, e); }, getElementsAtEvent: function(e) { return Chart.Interaction.modes.label(this, e, {intersect: true}); }, getElementsAtXAxis: function(e) { return Chart.Interaction.modes['x-axis'](this, e, {intersect: true}); }, getElementsAtEventForMode: function(e, mode, options) { var method = Chart.Interaction.modes[mode]; if (typeof method === 'function') { return method(this, e, options); } return []; }, getDatasetAtEvent: function(e) { return Chart.Interaction.modes.dataset(this, e, {intersect: true}); }, getDatasetMeta: function(datasetIndex) { var me = this; var dataset = me.data.datasets[datasetIndex]; if (!dataset._meta) { dataset._meta = {}; } var meta = dataset._meta[me.id]; if (!meta) { meta = dataset._meta[me.id] = { type: null, data: [], dataset: null, controller: null, hidden: null, // See isDatasetVisible() comment xAxisID: null, yAxisID: null }; } return meta; }, getVisibleDatasetCount: function() { var count = 0; for (var i = 0, ilen = this.data.datasets.length; i