[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Fmsystem-commits] [16367]
From: |
nelson . guerra |
Subject: |
[Fmsystem-commits] [16367] |
Date: |
Tue, 21 Feb 2017 14:17:02 -0500 (EST) |
Revision: 16367
http://svn.sv.gnu.org/viewvc/?view=rev&root=fmsystem&revision=16367
Author: nelson224
Date: 2017-02-21 14:17:02 -0500 (Tue, 21 Feb 2017)
Log Message:
-----------
Added Paths:
-----------
branches/dev-syncromind-2/phpgwapi/js/chart/
branches/dev-syncromind-2/phpgwapi/js/chart/Chart.js
branches/dev-syncromind-2/phpgwapi/js/chart/Chart.min.js
Added: branches/dev-syncromind-2/phpgwapi/js/chart/Chart.js
===================================================================
--- branches/dev-syncromind-2/phpgwapi/js/chart/Chart.js
(rev 0)
+++ branches/dev-syncromind-2/phpgwapi/js/chart/Chart.js 2017-02-21
19:17:02 UTC (rev 16367)
@@ -0,0 +1,12269 @@
+/*!
+ * 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<r.length;o++)s(r[o]);return
s})({1:[function(require,module,exports){
+
+},{}],2:[function(require,module,exports){
+/* MIT license */
+var colorNames = require(6);
+
+module.exports = {
+ getRgba: getRgba,
+ getHsla: getHsla,
+ getRgb: getRgb,
+ getHsl: getHsl,
+ getHwb: getHwb,
+ getAlpha: getAlpha,
+
+ hexString: hexString,
+ rgbString: rgbString,
+ rgbaString: rgbaString,
+ percentString: percentString,
+ percentaString: percentaString,
+ hslString: hslString,
+ hslaString: hslaString,
+ hwbString: hwbString,
+ keyword: keyword
+}
+
+function getRgba(string) {
+ if (!string) {
+ return;
+ }
+ var abbr = /^#([a-fA-F0-9]{3})$/,
+ hex = /^#([a-fA-F0-9]{6})$/,
+ rgba =
/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
+ per =
/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
+ keyword = /(\w+)/;
+
+ var rgb = [0, 0, 0],
+ a = 1,
+ match = string.match(abbr);
+ if (match) {
+ match = match[1];
+ for (var i = 0; i < rgb.length; i++) {
+ rgb[i] = parseInt(match[i] + match[i], 16);
+ }
+ }
+ else if (match = string.match(hex)) {
+ match = match[1];
+ for (var i = 0; i < rgb.length; i++) {
+ rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
+ }
+ }
+ else if (match = string.match(rgba)) {
+ for (var i = 0; i < rgb.length; i++) {
+ rgb[i] = parseInt(match[i + 1]);
+ }
+ a = parseFloat(match[4]);
+ }
+ else if (match = string.match(per)) {
+ for (var i = 0; i < rgb.length; i++) {
+ rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
+ }
+ a = parseFloat(match[4]);
+ }
+ else if (match = string.match(keyword)) {
+ if (match[1] == "transparent") {
+ return [0, 0, 0, 0];
+ }
+ rgb = colorNames[match[1]];
+ if (!rgb) {
+ return;
+ }
+ }
+
+ for (var i = 0; i < rgb.length; i++) {
+ rgb[i] = scale(rgb[i], 0, 255);
+ }
+ if (!a && a != 0) {
+ a = 1;
+ }
+ else {
+ a = scale(a, 0, 1);
+ }
+ rgb[3] = a;
+ return rgb;
+}
+
+function getHsla(string) {
+ if (!string) {
+ return;
+ }
+ var hsl =
/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
+ var match = string.match(hsl);
+ if (match) {
+ var alpha = parseFloat(match[4]);
+ var h = scale(parseInt(match[1]), 0, 360),
+ s = scale(parseFloat(match[2]), 0, 100),
+ l = scale(parseFloat(match[3]), 0, 100),
+ a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
+ return [h, s, l, a];
+ }
+}
+
+function getHwb(string) {
+ if (!string) {
+ return;
+ }
+ var hwb =
/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
+ var match = string.match(hwb);
+ if (match) {
+ var alpha = parseFloat(match[4]);
+ var h = scale(parseInt(match[1]), 0, 360),
+ w = scale(parseFloat(match[2]), 0, 100),
+ b = scale(parseFloat(match[3]), 0, 100),
+ a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
+ return [h, w, b, a];
+ }
+}
+
+function getRgb(string) {
+ var rgba = getRgba(string);
+ return rgba && rgba.slice(0, 3);
+}
+
+function getHsl(string) {
+ var hsla = getHsla(string);
+ return hsla && hsla.slice(0, 3);
+}
+
+function getAlpha(string) {
+ var vals = getRgba(string);
+ if (vals) {
+ return vals[3];
+ }
+ else if (vals = getHsla(string)) {
+ return vals[3];
+ }
+ else if (vals = getHwb(string)) {
+ return vals[3];
+ }
+}
+
+// generators
+function hexString(rgb) {
+ return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
+ + hexDouble(rgb[2]);
+}
+
+function rgbString(rgba, alpha) {
+ if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
+ return rgbaString(rgba, alpha);
+ }
+ return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
+}
+
+function rgbaString(rgba, alpha) {
+ if (alpha === undefined) {
+ alpha = (rgba[3] !== undefined ? rgba[3] : 1);
+ }
+ return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
+ + ", " + alpha + ")";
+}
+
+function percentString(rgba, alpha) {
+ if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
+ return percentaString(rgba, alpha);
+ }
+ var r = Math.round(rgba[0]/255 * 100),
+ g = Math.round(rgba[1]/255 * 100),
+ b = Math.round(rgba[2]/255 * 100);
+
+ return "rgb(" + r + "%, " + g + "%, " + b + "%)";
+}
+
+function percentaString(rgba, alpha) {
+ var r = Math.round(rgba[0]/255 * 100),
+ g = Math.round(rgba[1]/255 * 100),
+ b = Math.round(rgba[2]/255 * 100);
+ return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] ||
1) + ")";
+}
+
+function hslString(hsla, alpha) {
+ if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
+ return hslaString(hsla, alpha);
+ }
+ return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
+}
+
+function hslaString(hsla, alpha) {
+ if (alpha === undefined) {
+ alpha = (hsla[3] !== undefined ? hsla[3] : 1);
+ }
+ return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
+ + alpha + ")";
+}
+
+// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha
specific syntax
+// (hwb have alpha optional & 1 is default value)
+function hwbString(hwb, alpha) {
+ if (alpha === undefined) {
+ alpha = (hwb[3] !== undefined ? hwb[3] : 1);
+ }
+ return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
+ + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
+}
+
+function keyword(rgb) {
+ return reverseNames[rgb.slice(0, 3)];
+}
+
+// helpers
+function scale(num, min, max) {
+ return Math.min(Math.max(min, num), max);
+}
+
+function hexDouble(num) {
+ var str = num.toString(16).toUpperCase();
+ return (str.length < 2) ? "0" + str : str;
+}
+
+
+//create a list of reverse color names
+var reverseNames = {};
+for (var name in colorNames) {
+ reverseNames[colorNames[name]] = name;
+}
+
+},{"6":6}],3:[function(require,module,exports){
+/* MIT license */
+var convert = require(5);
+var string = require(2);
+
+var Color = function (obj) {
+ if (obj instanceof Color) {
+ return obj;
+ }
+ if (!(this instanceof Color)) {
+ return new Color(obj);
+ }
+
+ this.values = {
+ rgb: [0, 0, 0],
+ hsl: [0, 0, 0],
+ hsv: [0, 0, 0],
+ hwb: [0, 0, 0],
+ cmyk: [0, 0, 0, 0],
+ alpha: 1
+ };
+
+ // parse Color() argument
+ var vals;
+ if (typeof obj === 'string') {
+ vals = string.getRgba(obj);
+ if (vals) {
+ this.setValues('rgb', vals);
+ } else if (vals = string.getHsla(obj)) {
+ this.setValues('hsl', vals);
+ } else if (vals = string.getHwb(obj)) {
+ this.setValues('hwb', vals);
+ } else {
+ throw new Error('Unable to parse color from string "' +
obj + '"');
+ }
+ } else if (typeof obj === 'object') {
+ vals = obj;
+ if (vals.r !== undefined || vals.red !== undefined) {
+ this.setValues('rgb', vals);
+ } else if (vals.l !== undefined || vals.lightness !==
undefined) {
+ this.setValues('hsl', vals);
+ } else if (vals.v !== undefined || vals.value !== undefined) {
+ this.setValues('hsv', vals);
+ } else if (vals.w !== undefined || vals.whiteness !==
undefined) {
+ this.setValues('hwb', vals);
+ } else if (vals.c !== undefined || vals.cyan !== undefined) {
+ this.setValues('cmyk', vals);
+ } else {
+ throw new Error('Unable to parse color from object ' +
JSON.stringify(obj));
+ }
+ }
+};
+
+Color.prototype = {
+ rgb: function () {
+ return this.setSpace('rgb', arguments);
+ },
+ hsl: function () {
+ return this.setSpace('hsl', arguments);
+ },
+ hsv: function () {
+ return this.setSpace('hsv', arguments);
+ },
+ hwb: function () {
+ return this.setSpace('hwb', arguments);
+ },
+ cmyk: function () {
+ return this.setSpace('cmyk', arguments);
+ },
+
+ rgbArray: function () {
+ return this.values.rgb;
+ },
+ hslArray: function () {
+ return this.values.hsl;
+ },
+ hsvArray: function () {
+ return this.values.hsv;
+ },
+ hwbArray: function () {
+ var values = this.values;
+ if (values.alpha !== 1) {
+ return values.hwb.concat([values.alpha]);
+ }
+ return values.hwb;
+ },
+ cmykArray: function () {
+ return this.values.cmyk;
+ },
+ rgbaArray: function () {
+ var values = this.values;
+ return values.rgb.concat([values.alpha]);
+ },
+ hslaArray: function () {
+ var values = this.values;
+ return values.hsl.concat([values.alpha]);
+ },
+ alpha: function (val) {
+ if (val === undefined) {
+ return this.values.alpha;
+ }
+ this.setValues('alpha', val);
+ return this;
+ },
+
+ red: function (val) {
+ return this.setChannel('rgb', 0, val);
+ },
+ green: function (val) {
+ return this.setChannel('rgb', 1, val);
+ },
+ blue: function (val) {
+ return this.setChannel('rgb', 2, val);
+ },
+ hue: function (val) {
+ if (val) {
+ val %= 360;
+ val = val < 0 ? 360 + val : val;
+ }
+ return this.setChannel('hsl', 0, val);
+ },
+ saturation: function (val) {
+ return this.setChannel('hsl', 1, val);
+ },
+ lightness: function (val) {
+ return this.setChannel('hsl', 2, val);
+ },
+ saturationv: function (val) {
+ return this.setChannel('hsv', 1, val);
+ },
+ whiteness: function (val) {
+ return this.setChannel('hwb', 1, val);
+ },
+ blackness: function (val) {
+ return this.setChannel('hwb', 2, val);
+ },
+ value: function (val) {
+ return this.setChannel('hsv', 2, val);
+ },
+ cyan: function (val) {
+ return this.setChannel('cmyk', 0, val);
+ },
+ magenta: function (val) {
+ return this.setChannel('cmyk', 1, val);
+ },
+ yellow: function (val) {
+ return this.setChannel('cmyk', 2, val);
+ },
+ black: function (val) {
+ return this.setChannel('cmyk', 3, val);
+ },
+
+ hexString: function () {
+ return string.hexString(this.values.rgb);
+ },
+ rgbString: function () {
+ return string.rgbString(this.values.rgb, this.values.alpha);
+ },
+ rgbaString: function () {
+ return string.rgbaString(this.values.rgb, this.values.alpha);
+ },
+ percentString: function () {
+ return string.percentString(this.values.rgb, this.values.alpha);
+ },
+ hslString: function () {
+ return string.hslString(this.values.hsl, this.values.alpha);
+ },
+ hslaString: function () {
+ return string.hslaString(this.values.hsl, this.values.alpha);
+ },
+ hwbString: function () {
+ return string.hwbString(this.values.hwb, this.values.alpha);
+ },
+ keyword: function () {
+ return string.keyword(this.values.rgb, this.values.alpha);
+ },
+
+ rgbNumber: function () {
+ var rgb = this.values.rgb;
+ return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
+ },
+
+ luminosity: function () {
+ // http://www.w3.org/TR/WCAG20/#relativeluminancedef
+ var rgb = this.values.rgb;
+ var lum = [];
+ for (var i = 0; i < rgb.length; i++) {
+ var chan = rgb[i] / 255;
+ lum[i] = (chan <= 0.03928) ? chan / 12.92 :
Math.pow(((chan + 0.055) / 1.055), 2.4);
+ }
+ return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
+ },
+
+ contrast: function (color2) {
+ // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
+ var lum1 = this.luminosity();
+ var lum2 = color2.luminosity();
+ if (lum1 > 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('<ul class="' + chart.id + '-legend">');
+
+ 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('<li><span
style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
+ if (labels[i]) {
+ text.push(labels[i]);
+ }
+ text.push('</li>');
+ }
+ }
+
+ text.push('</ul>');
+ 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<ilen; ++i) {
+ me.updateElement(points[i], i, reset);
+ }
+
+ if (showLine && line._model.tension !== 0) {
+ me.updateBezierControlPoints();
+ }
+
+ // Now pivot the point for animation
+ for (i=0, ilen=points.length; i<ilen; ++i) {
+ points[i].pivot();
+ }
+ },
+
+ getPointBackgroundColor: function(point, index) {
+ var backgroundColor =
this.chart.options.elements.point.backgroundColor;
+ var dataset = this.getDataset();
+ var custom = point.custom || {};
+
+ if (custom.backgroundColor) {
+ backgroundColor = custom.backgroundColor;
+ } else if (dataset.pointBackgroundColor) {
+ backgroundColor =
helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index,
backgroundColor);
+ } else if (dataset.backgroundColor) {
+ backgroundColor = dataset.backgroundColor;
+ }
+
+ return backgroundColor;
+ },
+
+ getPointBorderColor: function(point, index) {
+ var borderColor =
this.chart.options.elements.point.borderColor;
+ var dataset = this.getDataset();
+ var custom = point.custom || {};
+
+ if (custom.borderColor) {
+ borderColor = custom.borderColor;
+ } else if (dataset.pointBorderColor) {
+ borderColor =
helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
+ } else if (dataset.borderColor) {
+ borderColor = dataset.borderColor;
+ }
+
+ return borderColor;
+ },
+
+ getPointBorderWidth: function(point, index) {
+ var borderWidth =
this.chart.options.elements.point.borderWidth;
+ var dataset = this.getDataset();
+ var custom = point.custom || {};
+
+ if (!isNaN(custom.borderWidth)) {
+ borderWidth = custom.borderWidth;
+ } else if (!isNaN(dataset.pointBorderWidth)) {
+ borderWidth =
helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
+ } else if (!isNaN(dataset.borderWidth)) {
+ borderWidth = dataset.borderWidth;
+ }
+
+ return borderWidth;
+ },
+
+ updateElement: function(point, index, reset) {
+ var me = this;
+ var meta = me.getMeta();
+ var custom = point.custom || {};
+ var dataset = me.getDataset();
+ var datasetIndex = me.index;
+ var value = dataset.data[index];
+ var yScale = me.getScaleForId(meta.yAxisID);
+ var xScale = me.getScaleForId(meta.xAxisID);
+ var pointOptions = me.chart.options.elements.point;
+ var x, y;
+ var labels = me.chart.data.labels || [];
+ var includeOffset = (labels.length === 1 ||
dataset.data.length === 1) || me.chart.isCombo;
+
+ // Compatibility: If the properties are defined with
only the old name, use those values
+ if ((dataset.radius !== undefined) &&
(dataset.pointRadius === undefined)) {
+ dataset.pointRadius = dataset.radius;
+ }
+ if ((dataset.hitRadius !== undefined) &&
(dataset.pointHitRadius === undefined)) {
+ dataset.pointHitRadius = dataset.hitRadius;
+ }
+
+ x = xScale.getPixelForValue(typeof value === 'object' ?
value : NaN, index, datasetIndex, includeOffset);
+ y = reset ? yScale.getBasePixel() :
me.calculatePointY(value, index, datasetIndex);
+
+ // Utility
+ point._xScale = xScale;
+ point._yScale = yScale;
+ point._datasetIndex = datasetIndex;
+ point._index = index;
+
+ // Desired view properties
+ point._model = {
+ x: x,
+ y: y,
+ skip: custom.skip || isNaN(x) || isNaN(y),
+ // Appearance
+ radius: custom.radius ||
helpers.getValueAtIndexOrDefault(dataset.pointRadius, index,
pointOptions.radius),
+ pointStyle: custom.pointStyle ||
helpers.getValueAtIndexOrDefault(dataset.pointStyle, index,
pointOptions.pointStyle),
+ backgroundColor:
me.getPointBackgroundColor(point, index),
+ borderColor: me.getPointBorderColor(point,
index),
+ borderWidth: me.getPointBorderWidth(point,
index),
+ tension: meta.dataset._model ?
meta.dataset._model.tension : 0,
+ steppedLine: meta.dataset._model ?
meta.dataset._model.steppedLine : false,
+ // Tooltip
+ hitRadius: custom.hitRadius ||
helpers.getValueAtIndexOrDefault(dataset.pointHitRadius, index,
pointOptions.hitRadius)
+ };
+ },
+
+ calculatePointY: function(value, index, datasetIndex) {
+ var me = this;
+ var chart = me.chart;
+ var meta = me.getMeta();
+ var yScale = me.getScaleForId(meta.yAxisID);
+ var sumPos = 0;
+ var sumNeg = 0;
+ var i, ds, dsMeta;
+
+ if (yScale.options.stacked) {
+ for (i = 0; i < datasetIndex; i++) {
+ ds = chart.data.datasets[i];
+ dsMeta = chart.getDatasetMeta(i);
+ if (dsMeta.type === 'line' &&
dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
+ var stackedRightValue =
Number(yScale.getRightValue(ds.data[index]));
+ if (stackedRightValue < 0) {
+ sumNeg +=
stackedRightValue || 0;
+ } else {
+ sumPos +=
stackedRightValue || 0;
+ }
+ }
+ }
+
+ var rightValue =
Number(yScale.getRightValue(value));
+ if (rightValue < 0) {
+ return yScale.getPixelForValue(sumNeg +
rightValue);
+ }
+ return yScale.getPixelForValue(sumPos +
rightValue);
+ }
+
+ return yScale.getPixelForValue(value);
+ },
+
+ updateBezierControlPoints: function() {
+ var me = this;
+ var meta = me.getMeta();
+ var area = me.chart.chartArea;
+ var points = (meta.data || []);
+ var i, ilen, point, model, controlPoints;
+
+ // Only consider points that are drawn in case the
spanGaps option is used
+ if (meta.dataset._model.spanGaps) {
+ points = points.filter(function(pt) {
+ return !pt._model.skip;
+ });
+ }
+
+ function capControlPoint(pt, min, max) {
+ return Math.max(Math.min(pt, max), min);
+ }
+
+ if (meta.dataset._model.cubicInterpolationMode ===
'monotone') {
+ helpers.splineCurveMonotone(points);
+ } else {
+ for (i = 0, ilen = points.length; i < ilen;
++i) {
+ point = points[i];
+ model = point._model;
+ controlPoints = helpers.splineCurve(
+ helpers.previousItem(points,
i)._model,
+ model,
+ helpers.nextItem(points,
i)._model,
+ meta.dataset._model.tension
+ );
+ model.controlPointPreviousX =
controlPoints.previous.x;
+ model.controlPointPreviousY =
controlPoints.previous.y;
+ model.controlPointNextX =
controlPoints.next.x;
+ model.controlPointNextY =
controlPoints.next.y;
+ }
+ }
+
+ if (me.chart.options.elements.line.capBezierPoints) {
+ for (i = 0, ilen = points.length; i < ilen;
++i) {
+ model = points[i]._model;
+ model.controlPointPreviousX =
capControlPoint(model.controlPointPreviousX, area.left, area.right);
+ model.controlPointPreviousY =
capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
+ model.controlPointNextX =
capControlPoint(model.controlPointNextX, area.left, area.right);
+ model.controlPointNextY =
capControlPoint(model.controlPointNextY, area.top, area.bottom);
+ }
+ }
+ },
+
+ draw: function(ease) {
+ var me = this;
+ var meta = me.getMeta();
+ var points = meta.data || [];
+ var easingDecimal = ease || 1;
+ var i, ilen;
+
+ // Transition Point Locations
+ for (i=0, ilen=points.length; i<ilen; ++i) {
+ points[i].transition(easingDecimal);
+ }
+
+ Chart.canvasHelpers.clipArea(me.chart.chart.ctx,
me.chart.chartArea);
+ // Transition and Draw the line
+ if (lineEnabled(me.getDataset(), me.chart.options)) {
+ meta.dataset.transition(easingDecimal).draw();
+ }
+ Chart.canvasHelpers.unclipArea(me.chart.chart.ctx);
+
+ // Draw the points
+ for (i=0, ilen=points.length; i<ilen; ++i) {
+ points[i].draw(me.chart.chartArea);
+ }
+ },
+
+ setHoverStyle: function(point) {
+ // Point
+ var dataset =
this.chart.data.datasets[point._datasetIndex];
+ var index = point._index;
+ var custom = point.custom || {};
+ var model = point._model;
+
+ model.radius = custom.hoverRadius ||
helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index,
this.chart.options.elements.point.hoverRadius);
+ model.backgroundColor = custom.hoverBackgroundColor ||
helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index,
helpers.getHoverColor(model.backgroundColor));
+ model.borderColor = custom.hoverBorderColor ||
helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index,
helpers.getHoverColor(model.borderColor));
+ model.borderWidth = custom.hoverBorderWidth ||
helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index,
model.borderWidth);
+ },
+
+ removeHoverStyle: function(point) {
+ var me = this;
+ var dataset =
me.chart.data.datasets[point._datasetIndex];
+ var index = point._index;
+ var custom = point.custom || {};
+ var model = point._model;
+
+ // Compatibility: If the properties are defined with
only the old name, use those values
+ if ((dataset.radius !== undefined) &&
(dataset.pointRadius === undefined)) {
+ dataset.pointRadius = dataset.radius;
+ }
+
+ model.radius = custom.radius ||
helpers.getValueAtIndexOrDefault(dataset.pointRadius, index,
me.chart.options.elements.point.radius);
+ model.backgroundColor =
me.getPointBackgroundColor(point, index);
+ model.borderColor = me.getPointBorderColor(point,
index);
+ model.borderWidth = me.getPointBorderWidth(point,
index);
+ }
+ });
+};
+
+},{}],19:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ Chart.defaults.polarArea = {
+
+ scale: {
+ type: 'radialLinear',
+ lineArc: true, // so that lines are circular
+ ticks: {
+ beginAtZero: true
+ }
+ },
+
+ // Boolean - Whether to animate the rotation of the chart
+ animation: {
+ animateRotate: true,
+ animateScale: true
+ },
+
+ startAngle: -0.5 * Math.PI,
+ aspectRatio: 1,
+ legendCallback: function(chart) {
+ var text = [];
+ text.push('<ul class="' + chart.id + '-legend">');
+
+ 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('<li><span
style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
+ if (labels[i]) {
+ text.push(labels[i]);
+ }
+ text.push('</li>');
+ }
+ }
+
+ text.push('</ul>');
+ 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<ilen; ++i) {
+ if (this.isDatasetVisible(i)) {
+ count++;
+ }
+ }
+ return count;
+ },
+
+ isDatasetVisible: function(datasetIndex) {
+ var meta = this.getDatasetMeta(datasetIndex);
+
+ // meta.hidden is a per chart dataset hidden flag
override with 3 states: if true or false,
+ // the dataset.hidden value is ignored, else if null,
the dataset hidden state is returned.
+ return typeof meta.hidden === 'boolean'? !meta.hidden :
!this.data.datasets[datasetIndex].hidden;
+ },
+
+ generateLegend: function() {
+ return this.options.legendCallback(this);
+ },
+
+ destroy: function() {
+ var me = this;
+ var canvas = me.chart.canvas;
+ var meta, i, ilen;
+
+ me.stop();
+
+ // dataset controllers need to cleanup associated data
+ for (i = 0, ilen = me.data.datasets.length; i < ilen;
++i) {
+ meta = me.getDatasetMeta(i);
+ if (meta.controller) {
+ meta.controller.destroy();
+ meta.controller = null;
+ }
+ }
+
+ if (canvas) {
+ me.unbindEvents();
+ helpers.clear(me.chart);
+ platform.releaseContext(me.chart.ctx);
+ me.chart.canvas = null;
+ me.chart.ctx = null;
+ }
+
+ plugins.notify(me, 'destroy');
+
+ delete Chart.instances[me.id];
+ },
+
+ toBase64Image: function() {
+ return
this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments);
+ },
+
+ initToolTip: function() {
+ var me = this;
+ me.tooltip = new Chart.Tooltip({
+ _chart: me.chart,
+ _chartInstance: me,
+ _data: me.data,
+ _options: me.options.tooltips
+ }, me);
+ me.tooltip.initialize();
+ },
+
+ /**
+ * @private
+ */
+ bindEvents: function() {
+ var me = this;
+ var listeners = me._listeners = {};
+ var listener = function() {
+ me.eventHandler.apply(me, arguments);
+ };
+
+ helpers.each(me.options.events, function(type) {
+ platform.addEventListener(me, type, listener);
+ listeners[type] = listener;
+ });
+
+ // Responsiveness is currently based on the use of an
iframe, however this method causes
+ // performance issues and could be troublesome when
used with ad blockers. So make sure
+ // that the user is still able to create a chart
without iframe when responsive is false.
+ // See https://github.com/chartjs/Chart.js/issues/2210
+ if (me.options.responsive) {
+ listener = function() {
+ me.resize();
+ };
+
+ platform.addEventListener(me, 'resize',
listener);
+ listeners.resize = listener;
+ }
+ },
+
+ /**
+ * @private
+ */
+ unbindEvents: function() {
+ var me = this;
+ var listeners = me._listeners;
+ if (!listeners) {
+ return;
+ }
+
+ delete me._listeners;
+ helpers.each(listeners, function(listener, type) {
+ platform.removeEventListener(me, type,
listener);
+ });
+ },
+
+ updateHoverStyle: function(elements, mode, enabled) {
+ var method = enabled? 'setHoverStyle' :
'removeHoverStyle';
+ var element, i, ilen;
+
+ for (i=0, ilen=elements.length; i<ilen; ++i) {
+ element = elements[i];
+ if (element) {
+
this.getDatasetMeta(element._datasetIndex).controller[method](element);
+ }
+ }
+ },
+
+ /**
+ * @private
+ */
+ eventHandler: function(e) {
+ var me = this;
+ var tooltip = me.tooltip;
+
+ if (plugins.notify(me, 'beforeEvent', [e]) === false) {
+ return;
+ }
+
+ // Buffer any update calls so that renders do not occur
+ me._bufferedRender = true;
+ me._bufferedRequest = null;
+
+ var changed = me.handleEvent(e);
+ changed |= tooltip && tooltip.handleEvent(e);
+
+ plugins.notify(me, 'afterEvent', [e]);
+
+ var bufferedRequest = me._bufferedRequest;
+ if (bufferedRequest) {
+ // If we have an update that was triggered, we
need to do a normal render
+ me.render(bufferedRequest.duration,
bufferedRequest.lazy);
+ } else if (changed && !me.animating) {
+ // If entering, leaving, or changing elements,
animate the change via pivot
+ me.stop();
+
+ // We only need to render at this point.
Updating will cause scales to be
+ // recomputed generating flicker & using more
memory than necessary.
+ me.render(me.options.hover.animationDuration,
true);
+ }
+
+ me._bufferedRender = false;
+ me._bufferedRequest = null;
+
+ return me;
+ },
+
+ /**
+ * Handle an event
+ * @private
+ * @param {IEvent} event the event to handle
+ * @return {Boolean} true if the chart needs to re-render
+ */
+ handleEvent: function(e) {
+ var me = this;
+ var options = me.options || {};
+ var hoverOptions = options.hover;
+ var changed = false;
+
+ me.lastActive = me.lastActive || [];
+
+ // Find Active Elements for hover and tooltips
+ if (e.type === 'mouseout') {
+ me.active = [];
+ } else {
+ me.active = me.getElementsAtEventForMode(e,
hoverOptions.mode, hoverOptions);
+ }
+
+ // On Hover hook
+ if (hoverOptions.onHover) {
+ // Need to call with native event here to not
break backwards compatibility
+ hoverOptions.onHover.call(me, e.native,
me.active);
+ }
+
+ if (e.type === 'mouseup' || e.type === 'click') {
+ if (options.onClick) {
+ // Use e.native here for backwards
compatibility
+ options.onClick.call(me, e.native,
me.active);
+ }
+ }
+
+ // Remove styling for last active (even if it may still
be active)
+ if (me.lastActive.length) {
+ me.updateHoverStyle(me.lastActive,
hoverOptions.mode, false);
+ }
+
+ // Built in hover styling
+ if (me.active.length && hoverOptions.mode) {
+ me.updateHoverStyle(me.active,
hoverOptions.mode, true);
+ }
+
+ changed = !helpers.arrayEquals(me.active,
me.lastActive);
+
+ // Remember Last Actives
+ me.lastActive = me.active;
+
+ return changed;
+ }
+ });
+};
+
+},{}],24:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
+
+ /**
+ * Hooks the array methods that add or remove values ('push', pop',
'shift', 'splice',
+ * 'unshift') and notify the listener AFTER the array has been altered.
Listeners are
+ * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same
arguments.
+ */
+ function listenArrayEvents(array, listener) {
+ if (array._chartjs) {
+ array._chartjs.listeners.push(listener);
+ return;
+ }
+
+ Object.defineProperty(array, '_chartjs', {
+ configurable: true,
+ enumerable: false,
+ value: {
+ listeners: [listener]
+ }
+ });
+
+ arrayEvents.forEach(function(key) {
+ var method = 'onData' + key.charAt(0).toUpperCase() +
key.slice(1);
+ var base = array[key];
+
+ Object.defineProperty(array, key, {
+ configurable: true,
+ enumerable: false,
+ value: function() {
+ var args =
Array.prototype.slice.call(arguments);
+ var res = base.apply(this, args);
+
+ helpers.each(array._chartjs.listeners,
function(object) {
+ if (typeof object[method] ===
'function') {
+
object[method].apply(object, args);
+ }
+ });
+
+ return res;
+ }
+ });
+ });
+ }
+
+ /**
+ * Removes the given array event listener and cleanup extra attached
properties (such as
+ * the _chartjs stub and overridden methods) if array doesn't have any
more listeners.
+ */
+ function unlistenArrayEvents(array, listener) {
+ var stub = array._chartjs;
+ if (!stub) {
+ return;
+ }
+
+ var listeners = stub.listeners;
+ var index = listeners.indexOf(listener);
+ if (index !== -1) {
+ listeners.splice(index, 1);
+ }
+
+ if (listeners.length > 0) {
+ return;
+ }
+
+ arrayEvents.forEach(function(key) {
+ delete array[key];
+ });
+
+ delete array._chartjs;
+ }
+
+ // Base class for all dataset controllers (line, bar, etc)
+ Chart.DatasetController = function(chart, datasetIndex) {
+ this.initialize(chart, datasetIndex);
+ };
+
+ helpers.extend(Chart.DatasetController.prototype, {
+
+ /**
+ * Element type used to generate a meta dataset (e.g.
Chart.element.Line).
+ * @type {Chart.core.element}
+ */
+ datasetElementType: null,
+
+ /**
+ * Element type used to generate a meta data (e.g.
Chart.element.Point).
+ * @type {Chart.core.element}
+ */
+ dataElementType: null,
+
+ initialize: function(chart, datasetIndex) {
+ var me = this;
+ me.chart = chart;
+ me.index = datasetIndex;
+ me.linkScales();
+ me.addElements();
+ },
+
+ updateIndex: function(datasetIndex) {
+ this.index = datasetIndex;
+ },
+
+ linkScales: function() {
+ var me = this;
+ var meta = me.getMeta();
+ var dataset = me.getDataset();
+
+ if (meta.xAxisID === null) {
+ meta.xAxisID = dataset.xAxisID ||
me.chart.options.scales.xAxes[0].id;
+ }
+ if (meta.yAxisID === null) {
+ meta.yAxisID = dataset.yAxisID ||
me.chart.options.scales.yAxes[0].id;
+ }
+ },
+
+ getDataset: function() {
+ return this.chart.data.datasets[this.index];
+ },
+
+ getMeta: function() {
+ return this.chart.getDatasetMeta(this.index);
+ },
+
+ getScaleForId: function(scaleID) {
+ return this.chart.scales[scaleID];
+ },
+
+ reset: function() {
+ this.update(true);
+ },
+
+ /**
+ * @private
+ */
+ destroy: function() {
+ if (this._data) {
+ unlistenArrayEvents(this._data, this);
+ }
+ },
+
+ createMetaDataset: function() {
+ var me = this;
+ var type = me.datasetElementType;
+ return type && new type({
+ _chart: me.chart.chart,
+ _datasetIndex: me.index
+ });
+ },
+
+ createMetaData: function(index) {
+ var me = this;
+ var type = me.dataElementType;
+ return type && new type({
+ _chart: me.chart.chart,
+ _datasetIndex: me.index,
+ _index: index
+ });
+ },
+
+ addElements: function() {
+ var me = this;
+ var meta = me.getMeta();
+ var data = me.getDataset().data || [];
+ var metaData = meta.data;
+ var i, ilen;
+
+ for (i=0, ilen=data.length; i<ilen; ++i) {
+ metaData[i] = metaData[i] ||
me.createMetaData(i);
+ }
+
+ meta.dataset = meta.dataset || me.createMetaDataset();
+ },
+
+ addElementAndReset: function(index) {
+ var element = this.createMetaData(index);
+ this.getMeta().data.splice(index, 0, element);
+ this.updateElement(element, index, true);
+ },
+
+ buildOrUpdateElements: function() {
+ var me = this;
+ var dataset = me.getDataset();
+ var data = dataset.data || (dataset.data = []);
+
+ // In order to correctly handle data addition/deletion
animation (an thus simulate
+ // real-time charts), we need to monitor these data
modifications and synchronize
+ // the internal meta data accordingly.
+ if (me._data !== data) {
+ if (me._data) {
+ // This case happens when the user
replaced the data array instance.
+ unlistenArrayEvents(me._data, me);
+ }
+
+ listenArrayEvents(data, me);
+ me._data = data;
+ }
+
+ // Re-sync meta data in case the user replaced the data
array or if we missed
+ // any updates and so make sure that we handle number
of datapoints changing.
+ me.resyncElements();
+ },
+
+ update: helpers.noop,
+
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+ var i, len;
+ var metaData = this.getMeta().data;
+ for (i = 0, len = metaData.length; i < len; ++i) {
+ metaData[i].transition(easingDecimal).draw();
+ }
+ },
+
+ removeHoverStyle: function(element, elementOpts) {
+ var dataset =
this.chart.data.datasets[element._datasetIndex],
+ index = element._index,
+ custom = element.custom || {},
+ valueOrDefault =
helpers.getValueAtIndexOrDefault,
+ model = element._model;
+
+ model.backgroundColor = custom.backgroundColor ?
custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index,
elementOpts.backgroundColor);
+ model.borderColor = custom.borderColor ?
custom.borderColor : valueOrDefault(dataset.borderColor, index,
elementOpts.borderColor);
+ model.borderWidth = custom.borderWidth ?
custom.borderWidth : valueOrDefault(dataset.borderWidth, index,
elementOpts.borderWidth);
+ },
+
+ setHoverStyle: function(element) {
+ var dataset =
this.chart.data.datasets[element._datasetIndex],
+ index = element._index,
+ custom = element.custom || {},
+ valueOrDefault =
helpers.getValueAtIndexOrDefault,
+ getHoverColor = helpers.getHoverColor,
+ model = element._model;
+
+ model.backgroundColor = custom.hoverBackgroundColor ?
custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor,
index, getHoverColor(model.backgroundColor));
+ model.borderColor = custom.hoverBorderColor ?
custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index,
getHoverColor(model.borderColor));
+ model.borderWidth = custom.hoverBorderWidth ?
custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index,
model.borderWidth);
+ },
+
+ /**
+ * @private
+ */
+ resyncElements: function() {
+ var me = this;
+ var meta = me.getMeta();
+ var data = me.getDataset().data;
+ var numMeta = meta.data.length;
+ var numData = data.length;
+
+ if (numData < numMeta) {
+ meta.data.splice(numData, numMeta - numData);
+ } else if (numData > numMeta) {
+ me.insertElements(numMeta, numData - numMeta);
+ }
+ },
+
+ /**
+ * @private
+ */
+ insertElements: function(start, count) {
+ for (var i=0; i<count; ++i) {
+ this.addElementAndReset(start + i);
+ }
+ },
+
+ /**
+ * @private
+ */
+ onDataPush: function() {
+ this.insertElements(this.getDataset().data.length-1,
arguments.length);
+ },
+
+ /**
+ * @private
+ */
+ onDataPop: function() {
+ this.getMeta().data.pop();
+ },
+
+ /**
+ * @private
+ */
+ onDataShift: function() {
+ this.getMeta().data.shift();
+ },
+
+ /**
+ * @private
+ */
+ onDataSplice: function(start, count) {
+ this.getMeta().data.splice(start, count);
+ this.insertElements(start, arguments.length - 2);
+ },
+
+ /**
+ * @private
+ */
+ onDataUnshift: function() {
+ this.insertElements(0, arguments.length);
+ }
+ });
+
+ Chart.DatasetController.extend = helpers.inherits;
+};
+
+},{}],25:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ Chart.elements = {};
+
+ Chart.Element = function(configuration) {
+ helpers.extend(this, configuration);
+ this.initialize.apply(this, arguments);
+ };
+
+ helpers.extend(Chart.Element.prototype, {
+
+ initialize: function() {
+ this.hidden = false;
+ },
+
+ pivot: function() {
+ var me = this;
+ if (!me._view) {
+ me._view = helpers.clone(me._model);
+ }
+ me._start = helpers.clone(me._view);
+ return me;
+ },
+
+ transition: function(ease) {
+ var me = this;
+
+ if (!me._view) {
+ me._view = helpers.clone(me._model);
+ }
+
+ // No animation -> No Transition
+ if (ease === 1) {
+ me._view = me._model;
+ me._start = null;
+ return me;
+ }
+
+ if (!me._start) {
+ me.pivot();
+ }
+
+ helpers.each(me._model, function(value, key) {
+
+ if (key[0] === '_') {
+ // Only non-underscored properties
+ // Init if doesn't exist
+ } else if (!me._view.hasOwnProperty(key)) {
+ if (typeof value === 'number' &&
!isNaN(me._view[key])) {
+ me._view[key] = value * ease;
+ } else {
+ me._view[key] = value;
+ }
+ // No unnecessary computations
+ } else if (value === me._view[key]) {
+ // It's the same! Woohoo!
+ // Color transitions if possible
+ } else if (typeof value === 'string') {
+ try {
+ var color =
helpers.color(me._model[key]).mix(helpers.color(me._start[key]), ease);
+ me._view[key] =
color.rgbString();
+ } catch (err) {
+ me._view[key] = value;
+ }
+ // Number transitions
+ } else if (typeof value === 'number') {
+ var startVal = me._start[key] !==
undefined && isNaN(me._start[key]) === false ? me._start[key] : 0;
+ me._view[key] = ((me._model[key] -
startVal) * ease) + startVal;
+ // Everything else
+ } else {
+ me._view[key] = value;
+ }
+ }, me);
+
+ return me;
+ },
+
+ tooltipPosition: function() {
+ return {
+ x: this._model.x,
+ y: this._model.y
+ };
+ },
+
+ hasValue: function() {
+ return helpers.isNumber(this._model.x) &&
helpers.isNumber(this._model.y);
+ }
+ });
+
+ Chart.Element.extend = helpers.inherits;
+
+};
+
+},{}],26:[function(require,module,exports){
+/* global window: false */
+/* global document: false */
+'use strict';
+
+var color = require(3);
+
+module.exports = function(Chart) {
+ // Global Chart helpers object for utility methods and classes
+ var helpers = Chart.helpers = {};
+
+ // -- Basic js utility methods
+ helpers.each = function(loopable, callback, self, reverse) {
+ // Check to see if null or undefined firstly.
+ var i, len;
+ if (helpers.isArray(loopable)) {
+ len = loopable.length;
+ if (reverse) {
+ for (i = len - 1; i >= 0; i--) {
+ callback.call(self, loopable[i], i);
+ }
+ } else {
+ for (i = 0; i < len; i++) {
+ callback.call(self, loopable[i], i);
+ }
+ }
+ } else if (typeof loopable === 'object') {
+ var keys = Object.keys(loopable);
+ len = keys.length;
+ for (i = 0; i < len; i++) {
+ callback.call(self, loopable[keys[i]], keys[i]);
+ }
+ }
+ };
+ helpers.clone = function(obj) {
+ var objClone = {};
+ helpers.each(obj, function(value, key) {
+ if (helpers.isArray(value)) {
+ objClone[key] = value.slice(0);
+ } else if (typeof value === 'object' && value !== null)
{
+ objClone[key] = helpers.clone(value);
+ } else {
+ objClone[key] = value;
+ }
+ });
+ return objClone;
+ };
+ helpers.extend = function(base) {
+ var setFn = function(value, key) {
+ base[key] = value;
+ };
+ for (var i = 1, ilen = arguments.length; i < ilen; i++) {
+ helpers.each(arguments[i], setFn);
+ }
+ return base;
+ };
+ // Need a special merge function to chart configs since they are now
grouped
+ helpers.configMerge = function(_base) {
+ var base = helpers.clone(_base);
+ helpers.each(Array.prototype.slice.call(arguments, 1),
function(extension) {
+ helpers.each(extension, function(value, key) {
+ var baseHasProperty = base.hasOwnProperty(key);
+ var baseVal = baseHasProperty ? base[key] : {};
+
+ if (key === 'scales') {
+ // Scale config merging is complex. Add
our own function here for that
+ base[key] = helpers.scaleMerge(baseVal,
value);
+ } else if (key === 'scale') {
+ // Used in polar area & radar charts
since there is only one scale
+ base[key] =
helpers.configMerge(baseVal, Chart.scaleService.getScaleDefaults(value.type),
value);
+ } else if (baseHasProperty
+ && typeof baseVal === 'object'
+ && !helpers.isArray(baseVal)
+ && baseVal !== null
+ && typeof value === 'object'
+ && !helpers.isArray(value)) {
+ // If we are overwriting an object with
an object, do a merge of the properties.
+ base[key] =
helpers.configMerge(baseVal, value);
+ } else {
+ // can just overwrite the value in this
case
+ base[key] = value;
+ }
+ });
+ });
+
+ return base;
+ };
+ helpers.scaleMerge = function(_base, extension) {
+ var base = helpers.clone(_base);
+
+ helpers.each(extension, function(value, key) {
+ if (key === 'xAxes' || key === 'yAxes') {
+ // These properties are arrays of items
+ if (base.hasOwnProperty(key)) {
+ helpers.each(value, function(valueObj,
index) {
+ var axisType =
helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' :
'linear');
+ var axisDefaults =
Chart.scaleService.getScaleDefaults(axisType);
+ if (index >= base[key].length
|| !base[key][index].type) {
+
base[key].push(helpers.configMerge(axisDefaults, valueObj));
+ } else if (valueObj.type &&
valueObj.type !== base[key][index].type) {
+ // Type changed. Bring
in the new defaults before we bring in valueObj so that valueObj can override
the correct scale defaults
+ base[key][index] =
helpers.configMerge(base[key][index], axisDefaults, valueObj);
+ } else {
+ // Type is the same
+ base[key][index] =
helpers.configMerge(base[key][index], valueObj);
+ }
+ });
+ } else {
+ base[key] = [];
+ helpers.each(value, function(valueObj) {
+ var axisType =
helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' :
'linear');
+
base[key].push(helpers.configMerge(Chart.scaleService.getScaleDefaults(axisType),
valueObj));
+ });
+ }
+ } else if (base.hasOwnProperty(key) && typeof base[key]
=== 'object' && base[key] !== null && typeof value === 'object') {
+ // If we are overwriting an object with an
object, do a merge of the properties.
+ base[key] = helpers.configMerge(base[key],
value);
+
+ } else {
+ // can just overwrite the value in this case
+ base[key] = value;
+ }
+ });
+
+ return base;
+ };
+ helpers.getValueAtIndexOrDefault = function(value, index, defaultValue)
{
+ if (value === undefined || value === null) {
+ return defaultValue;
+ }
+
+ if (helpers.isArray(value)) {
+ return index < value.length ? value[index] :
defaultValue;
+ }
+
+ return value;
+ };
+ helpers.getValueOrDefault = function(value, defaultValue) {
+ return value === undefined ? defaultValue : value;
+ };
+ helpers.indexOf = Array.prototype.indexOf?
+ function(array, item) {
+ return array.indexOf(item);
+ }:
+ function(array, item) {
+ for (var i = 0, ilen = array.length; i < ilen; ++i) {
+ if (array[i] === item) {
+ return i;
+ }
+ }
+ return -1;
+ };
+ helpers.where = function(collection, filterCallback) {
+ if (helpers.isArray(collection) && Array.prototype.filter) {
+ return collection.filter(filterCallback);
+ }
+ var filtered = [];
+
+ helpers.each(collection, function(item) {
+ if (filterCallback(item)) {
+ filtered.push(item);
+ }
+ });
+
+ return filtered;
+ };
+ helpers.findIndex = Array.prototype.findIndex?
+ function(array, callback, scope) {
+ return array.findIndex(callback, scope);
+ } :
+ function(array, callback, scope) {
+ scope = scope === undefined? array : scope;
+ for (var i = 0, ilen = array.length; i < ilen; ++i) {
+ if (callback.call(scope, array[i], i, array)) {
+ return i;
+ }
+ }
+ return -1;
+ };
+ helpers.findNextWhere = function(arrayToSearch, filterCallback,
startIndex) {
+ // Default to start of the array
+ if (startIndex === undefined || startIndex === null) {
+ startIndex = -1;
+ }
+ for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
+ var currentItem = arrayToSearch[i];
+ if (filterCallback(currentItem)) {
+ return currentItem;
+ }
+ }
+ };
+ helpers.findPreviousWhere = function(arrayToSearch, filterCallback,
startIndex) {
+ // Default to end of the array
+ if (startIndex === undefined || startIndex === null) {
+ startIndex = arrayToSearch.length;
+ }
+ for (var i = startIndex - 1; i >= 0; i--) {
+ var currentItem = arrayToSearch[i];
+ if (filterCallback(currentItem)) {
+ return currentItem;
+ }
+ }
+ };
+ helpers.inherits = function(extensions) {
+ // Basic javascript inheritance based on the model created in
Backbone.js
+ var me = this;
+ var ChartElement = (extensions &&
extensions.hasOwnProperty('constructor')) ? extensions.constructor : function()
{
+ return me.apply(this, arguments);
+ };
+
+ var Surrogate = function() {
+ this.constructor = ChartElement;
+ };
+ Surrogate.prototype = me.prototype;
+ ChartElement.prototype = new Surrogate();
+
+ ChartElement.extend = helpers.inherits;
+
+ if (extensions) {
+ helpers.extend(ChartElement.prototype, extensions);
+ }
+
+ ChartElement.__super__ = me.prototype;
+
+ return ChartElement;
+ };
+ helpers.noop = function() {};
+ helpers.uid = (function() {
+ var id = 0;
+ return function() {
+ return id++;
+ };
+ }());
+ // -- Math methods
+ helpers.isNumber = function(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+ };
+ helpers.almostEquals = function(x, y, epsilon) {
+ return Math.abs(x - y) < epsilon;
+ };
+ helpers.almostWhole = function(x, epsilon) {
+ var rounded = Math.round(x);
+ return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
+ };
+ helpers.max = function(array) {
+ return array.reduce(function(max, value) {
+ if (!isNaN(value)) {
+ return Math.max(max, value);
+ }
+ return max;
+ }, Number.NEGATIVE_INFINITY);
+ };
+ helpers.min = function(array) {
+ return array.reduce(function(min, value) {
+ if (!isNaN(value)) {
+ return Math.min(min, value);
+ }
+ return min;
+ }, Number.POSITIVE_INFINITY);
+ };
+ helpers.sign = Math.sign?
+ function(x) {
+ return Math.sign(x);
+ } :
+ function(x) {
+ x = +x; // convert to a number
+ if (x === 0 || isNaN(x)) {
+ return x;
+ }
+ return x > 0 ? 1 : -1;
+ };
+ helpers.log10 = Math.log10?
+ function(x) {
+ return Math.log10(x);
+ } :
+ function(x) {
+ return Math.log(x) / Math.LN10;
+ };
+ helpers.toRadians = function(degrees) {
+ return degrees * (Math.PI / 180);
+ };
+ helpers.toDegrees = function(radians) {
+ return radians * (180 / Math.PI);
+ };
+ // Gets the angle from vertical upright to the point about a centre.
+ helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
+ var distanceFromXCenter = anglePoint.x - centrePoint.x,
+ distanceFromYCenter = anglePoint.y - centrePoint.y,
+ radialDistanceFromCenter =
Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter *
distanceFromYCenter);
+
+ var angle = Math.atan2(distanceFromYCenter,
distanceFromXCenter);
+
+ if (angle < (-0.5 * Math.PI)) {
+ angle += 2.0 * Math.PI; // make sure the returned angle
is in the range of (-PI/2, 3PI/2]
+ }
+
+ return {
+ angle: angle,
+ distance: radialDistanceFromCenter
+ };
+ };
+ helpers.distanceBetweenPoints = function(pt1, pt2) {
+ return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y -
pt1.y, 2));
+ };
+ helpers.aliasPixel = function(pixelWidth) {
+ return (pixelWidth % 2 === 0) ? 0 : 0.5;
+ };
+ helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
+ // Props to Rob Spencer at scaled innovation for his post on
splining between points
+ //
http://scaledinnovation.com/analytics/splines/aboutSplines.html
+
+ // This function must also respect "skipped" points
+
+ var previous = firstPoint.skip ? middlePoint : firstPoint,
+ current = middlePoint,
+ next = afterPoint.skip ? middlePoint : afterPoint;
+
+ var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) +
Math.pow(current.y - previous.y, 2));
+ var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) +
Math.pow(next.y - current.y, 2));
+
+ var s01 = d01 / (d01 + d12);
+ var s12 = d12 / (d01 + d12);
+
+ // If all points are the same, s01 & s02 will be inf
+ s01 = isNaN(s01) ? 0 : s01;
+ s12 = isNaN(s12) ? 0 : s12;
+
+ var fa = t * s01; // scaling factor for triangle Ta
+ var fb = t * s12;
+
+ return {
+ previous: {
+ x: current.x - fa * (next.x - previous.x),
+ y: current.y - fa * (next.y - previous.y)
+ },
+ next: {
+ x: current.x + fb * (next.x - previous.x),
+ y: current.y + fb * (next.y - previous.y)
+ }
+ };
+ };
+ helpers.EPSILON = Number.EPSILON || 1e-14;
+ helpers.splineCurveMonotone = function(points) {
+ // This function calculates Bézier control points in a similar
way than |splineCurve|,
+ // but preserves monotonicity of the provided data and ensures
no local extremums are added
+ // between the dataset discrete points due to the interpolation.
+ // See :
https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
+
+ var pointsWithTangents = (points || []).map(function(point) {
+ return {
+ model: point._model,
+ deltaK: 0,
+ mK: 0
+ };
+ });
+
+ // Calculate slopes (deltaK) and initialize tangents (mK)
+ var pointsLen = pointsWithTangents.length;
+ var i, pointBefore, pointCurrent, pointAfter;
+ for (i = 0; i < pointsLen; ++i) {
+ pointCurrent = pointsWithTangents[i];
+ if (pointCurrent.model.skip) {
+ continue;
+ }
+
+ pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
+ pointAfter = i < pointsLen - 1 ? pointsWithTangents[i +
1] : null;
+ if (pointAfter && !pointAfter.model.skip) {
+ var slopeDeltaX = (pointAfter.model.x -
pointCurrent.model.x);
+
+ // In the case of two points that appear at the
same x pixel, slopeDeltaX is 0
+ pointCurrent.deltaK = slopeDeltaX !== 0 ?
(pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
+ }
+
+ if (!pointBefore || pointBefore.model.skip) {
+ pointCurrent.mK = pointCurrent.deltaK;
+ } else if (!pointAfter || pointAfter.model.skip) {
+ pointCurrent.mK = pointBefore.deltaK;
+ } else if (this.sign(pointBefore.deltaK) !==
this.sign(pointCurrent.deltaK)) {
+ pointCurrent.mK = 0;
+ } else {
+ pointCurrent.mK = (pointBefore.deltaK +
pointCurrent.deltaK) / 2;
+ }
+ }
+
+ // Adjust tangents to ensure monotonic properties
+ var alphaK, betaK, tauK, squaredMagnitude;
+ for (i = 0; i < pointsLen - 1; ++i) {
+ pointCurrent = pointsWithTangents[i];
+ pointAfter = pointsWithTangents[i + 1];
+ if (pointCurrent.model.skip || pointAfter.model.skip) {
+ continue;
+ }
+
+ if (helpers.almostEquals(pointCurrent.deltaK, 0,
this.EPSILON)) {
+ pointCurrent.mK = pointAfter.mK = 0;
+ continue;
+ }
+
+ alphaK = pointCurrent.mK / pointCurrent.deltaK;
+ betaK = pointAfter.mK / pointCurrent.deltaK;
+ squaredMagnitude = Math.pow(alphaK, 2) +
Math.pow(betaK, 2);
+ if (squaredMagnitude <= 9) {
+ continue;
+ }
+
+ tauK = 3 / Math.sqrt(squaredMagnitude);
+ pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
+ pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
+ }
+
+ // Compute control points
+ var deltaX;
+ for (i = 0; i < pointsLen; ++i) {
+ pointCurrent = pointsWithTangents[i];
+ if (pointCurrent.model.skip) {
+ continue;
+ }
+
+ pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
+ pointAfter = i < pointsLen - 1 ? pointsWithTangents[i +
1] : null;
+ if (pointBefore && !pointBefore.model.skip) {
+ deltaX = (pointCurrent.model.x -
pointBefore.model.x) / 3;
+ pointCurrent.model.controlPointPreviousX =
pointCurrent.model.x - deltaX;
+ pointCurrent.model.controlPointPreviousY =
pointCurrent.model.y - deltaX * pointCurrent.mK;
+ }
+ if (pointAfter && !pointAfter.model.skip) {
+ deltaX = (pointAfter.model.x -
pointCurrent.model.x) / 3;
+ pointCurrent.model.controlPointNextX =
pointCurrent.model.x + deltaX;
+ pointCurrent.model.controlPointNextY =
pointCurrent.model.y + deltaX * pointCurrent.mK;
+ }
+ }
+ };
+ helpers.nextItem = function(collection, index, loop) {
+ if (loop) {
+ return index >= collection.length - 1 ? collection[0] :
collection[index + 1];
+ }
+ return index >= collection.length - 1 ?
collection[collection.length - 1] : collection[index + 1];
+ };
+ helpers.previousItem = function(collection, index, loop) {
+ if (loop) {
@@ Diff output truncated at 153600 characters. @@
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Fmsystem-commits] [16367],
nelson . guerra <=