diff --git a/composer.json b/composer.json
index 08f595c..7bc26e3 100644
--- a/composer.json
+++ b/composer.json
@@ -20,10 +20,9 @@
},
"require": {
- "php": ">=5.5",
- "contao/core": ">=3.4",
- "contao-community-alliance/composer-plugin": "~2",
- "kigkonsult/icalcreator": "*",
+ "contao-community-alliance/composer-plugin":"~2.4 || ~3.0",
+ "contao/core-bundle": "~3.5 || ~4.4",
+ "kigkonsult/icalcreator": "~2",
"phpfastcache/phpfastcache": "~5",
"irazasyed/telegram-bot-sdk": "~2"
},
@@ -43,10 +42,14 @@
"Simpletipp": "src/"
}
},
+ "config": {
+ "fxp-asset": {
+ "installer-paths": {
+ "bower-asset-library": "contao/assets"
+ }
+ }
+ },
"extra": {
- "asset-installer-paths": {
- "bower-asset-library": "contao/assets"
- },
"contao": {
"sources": {
"contao": "system/modules/simpletipp"
diff --git a/contao/assets/chartist/CHANGELOG.md b/contao/assets/chartist/CHANGELOG.md
index 8efd792..3e8b234 100644
--- a/contao/assets/chartist/CHANGELOG.md
+++ b/contao/assets/chartist/CHANGELOG.md
@@ -1,3 +1,8 @@
+v0.11.0 - 11 Apr 2017
+- Added CSP compatibility by using CSSOM instead of style attributes (Francisco Silva)
+- Added feature to render pie / donut chart as solid shape, allowing outlines (Sergey Kovalyov, Chris Carson)
+- Fixed XMLNS for foreignObjet content (Alfredo Matos)
+
v0.10.0 - 23 Oct 2016
---------------------
diff --git a/contao/assets/chartist/dist/chartist.css b/contao/assets/chartist/dist/chartist.css
index 35f27d8..bb19a80 100644
--- a/contao/assets/chartist/dist/chartist.css
+++ b/contao/assets/chartist/dist/chartist.css
@@ -168,91 +168,91 @@
.ct-series-a .ct-point, .ct-series-a .ct-line, .ct-series-a .ct-bar, .ct-series-a .ct-slice-donut {
stroke: #d70206; }
-.ct-series-a .ct-slice-pie, .ct-series-a .ct-area {
+.ct-series-a .ct-slice-pie, .ct-series-a .ct-slice-donut-solid, .ct-series-a .ct-area {
fill: #d70206; }
.ct-series-b .ct-point, .ct-series-b .ct-line, .ct-series-b .ct-bar, .ct-series-b .ct-slice-donut {
stroke: #f05b4f; }
-.ct-series-b .ct-slice-pie, .ct-series-b .ct-area {
+.ct-series-b .ct-slice-pie, .ct-series-b .ct-slice-donut-solid, .ct-series-b .ct-area {
fill: #f05b4f; }
.ct-series-c .ct-point, .ct-series-c .ct-line, .ct-series-c .ct-bar, .ct-series-c .ct-slice-donut {
stroke: #f4c63d; }
-.ct-series-c .ct-slice-pie, .ct-series-c .ct-area {
+.ct-series-c .ct-slice-pie, .ct-series-c .ct-slice-donut-solid, .ct-series-c .ct-area {
fill: #f4c63d; }
.ct-series-d .ct-point, .ct-series-d .ct-line, .ct-series-d .ct-bar, .ct-series-d .ct-slice-donut {
stroke: #d17905; }
-.ct-series-d .ct-slice-pie, .ct-series-d .ct-area {
+.ct-series-d .ct-slice-pie, .ct-series-d .ct-slice-donut-solid, .ct-series-d .ct-area {
fill: #d17905; }
.ct-series-e .ct-point, .ct-series-e .ct-line, .ct-series-e .ct-bar, .ct-series-e .ct-slice-donut {
stroke: #453d3f; }
-.ct-series-e .ct-slice-pie, .ct-series-e .ct-area {
+.ct-series-e .ct-slice-pie, .ct-series-e .ct-slice-donut-solid, .ct-series-e .ct-area {
fill: #453d3f; }
.ct-series-f .ct-point, .ct-series-f .ct-line, .ct-series-f .ct-bar, .ct-series-f .ct-slice-donut {
stroke: #59922b; }
-.ct-series-f .ct-slice-pie, .ct-series-f .ct-area {
+.ct-series-f .ct-slice-pie, .ct-series-f .ct-slice-donut-solid, .ct-series-f .ct-area {
fill: #59922b; }
.ct-series-g .ct-point, .ct-series-g .ct-line, .ct-series-g .ct-bar, .ct-series-g .ct-slice-donut {
stroke: #0544d3; }
-.ct-series-g .ct-slice-pie, .ct-series-g .ct-area {
+.ct-series-g .ct-slice-pie, .ct-series-g .ct-slice-donut-solid, .ct-series-g .ct-area {
fill: #0544d3; }
.ct-series-h .ct-point, .ct-series-h .ct-line, .ct-series-h .ct-bar, .ct-series-h .ct-slice-donut {
stroke: #6b0392; }
-.ct-series-h .ct-slice-pie, .ct-series-h .ct-area {
+.ct-series-h .ct-slice-pie, .ct-series-h .ct-slice-donut-solid, .ct-series-h .ct-area {
fill: #6b0392; }
.ct-series-i .ct-point, .ct-series-i .ct-line, .ct-series-i .ct-bar, .ct-series-i .ct-slice-donut {
stroke: #f05b4f; }
-.ct-series-i .ct-slice-pie, .ct-series-i .ct-area {
+.ct-series-i .ct-slice-pie, .ct-series-i .ct-slice-donut-solid, .ct-series-i .ct-area {
fill: #f05b4f; }
.ct-series-j .ct-point, .ct-series-j .ct-line, .ct-series-j .ct-bar, .ct-series-j .ct-slice-donut {
stroke: #dda458; }
-.ct-series-j .ct-slice-pie, .ct-series-j .ct-area {
+.ct-series-j .ct-slice-pie, .ct-series-j .ct-slice-donut-solid, .ct-series-j .ct-area {
fill: #dda458; }
.ct-series-k .ct-point, .ct-series-k .ct-line, .ct-series-k .ct-bar, .ct-series-k .ct-slice-donut {
stroke: #eacf7d; }
-.ct-series-k .ct-slice-pie, .ct-series-k .ct-area {
+.ct-series-k .ct-slice-pie, .ct-series-k .ct-slice-donut-solid, .ct-series-k .ct-area {
fill: #eacf7d; }
.ct-series-l .ct-point, .ct-series-l .ct-line, .ct-series-l .ct-bar, .ct-series-l .ct-slice-donut {
stroke: #86797d; }
-.ct-series-l .ct-slice-pie, .ct-series-l .ct-area {
+.ct-series-l .ct-slice-pie, .ct-series-l .ct-slice-donut-solid, .ct-series-l .ct-area {
fill: #86797d; }
.ct-series-m .ct-point, .ct-series-m .ct-line, .ct-series-m .ct-bar, .ct-series-m .ct-slice-donut {
stroke: #b2c326; }
-.ct-series-m .ct-slice-pie, .ct-series-m .ct-area {
+.ct-series-m .ct-slice-pie, .ct-series-m .ct-slice-donut-solid, .ct-series-m .ct-area {
fill: #b2c326; }
.ct-series-n .ct-point, .ct-series-n .ct-line, .ct-series-n .ct-bar, .ct-series-n .ct-slice-donut {
stroke: #6188e2; }
-.ct-series-n .ct-slice-pie, .ct-series-n .ct-area {
+.ct-series-n .ct-slice-pie, .ct-series-n .ct-slice-donut-solid, .ct-series-n .ct-area {
fill: #6188e2; }
.ct-series-o .ct-point, .ct-series-o .ct-line, .ct-series-o .ct-bar, .ct-series-o .ct-slice-donut {
stroke: #a748ca; }
-.ct-series-o .ct-slice-pie, .ct-series-o .ct-area {
+.ct-series-o .ct-slice-pie, .ct-series-o .ct-slice-donut-solid, .ct-series-o .ct-area {
fill: #a748ca; }
.ct-square {
diff --git a/contao/assets/chartist/dist/chartist.css.map b/contao/assets/chartist/dist/chartist.css.map
index cee2d40..106c076 100644
--- a/contao/assets/chartist/dist/chartist.css.map
+++ b/contao/assets/chartist/dist/chartist.css.map
@@ -5,6 +5,6 @@
"../../src/styles/chartist.scss",
"../../src/styles/settings/_chartist-settings.scss"
],
- "mappings": "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",
+ "mappings": "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",
"names": []
}
\ No newline at end of file
diff --git a/contao/assets/chartist/dist/chartist.js b/contao/assets/chartist/dist/chartist.js
index 050d0a6..322d8ad 100644
--- a/contao/assets/chartist/dist/chartist.js
+++ b/contao/assets/chartist/dist/chartist.js
@@ -4,7 +4,7 @@
define('Chartist', [], function () {
return (root['Chartist'] = factory());
});
- } else if (typeof exports === 'object') {
+ } else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
@@ -14,8 +14,8 @@
}
}(this, function () {
-/* Chartist.js 0.10.0
- * Copyright © 2016 Gion Kunz
+/* Chartist.js 0.11.0
+ * Copyright © 2017 Gion Kunz
* Free to use under either the WTFPL license or the MIT license.
* https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL
* https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT
@@ -26,7 +26,7 @@
* @module Chartist.Core
*/
var Chartist = {
- version: '0.10.0'
+ version: '0.11.0'
};
(function (window, document, Chartist) {
@@ -337,9 +337,10 @@ var Chartist = {
svg = new Chartist.Svg('svg').attr({
width: width,
height: height
- }).addClass(className).attr({
- style: 'width: ' + width + '; height: ' + height + ';'
- });
+ }).addClass(className);
+
+ svg._node.style.width = width;
+ svg._node.style.height = height;
// Add the DOM node to our container
container.appendChild(svg._node);
@@ -993,10 +994,12 @@ var Chartist = {
if(useForeignObject) {
// We need to set width and height explicitly to px as span will not expand with width and height being
// 100% in all browsers
- var content = '' +
- labels[index] + ' ';
+ var content = document.createElement('span');
+ content.className = classes.join(' ');
+ content.setAttribute('xmlns', Chartist.namespaces.xhtml);
+ content.innerText = labels[index];
+ content.style[axis.units.len] = Math.round(positionalData[axis.units.len]) + 'px';
+ content.style[axis.counterUnits.len] = Math.round(positionalData[axis.counterUnits.len]) + 'px';
labelElement = group.foreignObject(content, Chartist.extend({
style: 'overflow: visible;'
@@ -4116,6 +4119,7 @@ var Chartist = {
series: 'ct-series',
slicePie: 'ct-slice-pie',
sliceDonut: 'ct-slice-donut',
+ sliceDonutSolid: 'ct-slice-donut-solid',
label: 'ct-label'
},
// The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise.
@@ -4124,6 +4128,8 @@ var Chartist = {
total: undefined,
// If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices.
donut: false,
+ // If specified the donut segments will be drawn as shapes instead of strokes.
+ donutSolid: false,
// Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future.
// This option can be set as number or string to specify a relative width (i.e. 100 or '30%').
donutWidth: 60,
@@ -4199,15 +4205,17 @@ var Chartist = {
// If this is a donut chart we need to adjust our radius to enable strokes to be drawn inside
// Unfortunately this is not possible with the current SVG Spec
// See this proposal for more details: http://lists.w3.org/Archives/Public/www-svg/2003Oct/0000.html
- radius -= options.donut ? donutWidth.value / 2 : 0;
+ radius -= options.donut && !options.donutSolid ? donutWidth.value / 2 : 0;
// If labelPosition is set to `outside` or a donut chart is drawn then the label position is at the radius,
// if regular pie chart it's half of the radius
- if(options.labelPosition === 'outside' || options.donut) {
+ if(options.labelPosition === 'outside' || options.donut && !options.donutSolid) {
labelRadius = radius;
} else if(options.labelPosition === 'center') {
// If labelPosition is center we start with 0 and will later wait for the labelOffset
labelRadius = 0;
+ } else if(options.donutSolid) {
+ labelRadius = radius - donutWidth.value / 2;
} else {
// Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie
// slice
@@ -4268,21 +4276,38 @@ var Chartist = {
var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle),
end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle);
+ var innerStart,
+ innerEnd,
+ donutSolidRadius;
+
// Create a new path element for the pie chart. If this isn't a donut chart we should close the path for a correct stroke
- var path = new Chartist.Svg.Path(!options.donut)
+ var path = new Chartist.Svg.Path(!options.donut || options.donutSolid)
.move(end.x, end.y)
.arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y);
// If regular pie chart (no donut) we add a line to the center of the circle for completing the pie
if(!options.donut) {
path.line(center.x, center.y);
+ } else if (options.donutSolid) {
+ donutSolidRadius = radius - donutWidth.value;
+ innerStart = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2));
+ innerEnd = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, endAngle);
+ path.line(innerStart.x, innerStart.y);
+ path.arc(donutSolidRadius, donutSolidRadius, 0, endAngle - startAngle > 180, 1, innerEnd.x, innerEnd.y);
}
// Create the SVG path
// If this is a donut chart we add the donut class, otherwise just a regular slice
+ var pathClassName = options.classNames.slicePie;
+ if (options.donut) {
+ pathClassName = options.classNames.sliceDonut;
+ if (options.donutSolid) {
+ pathClassName = options.classNames.sliceDonutSolid;
+ }
+ }
var pathElement = seriesGroups[index].elem('path', {
d: path.stringify()
- }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie);
+ }, pathClassName);
// Adding the pie series value to the path
pathElement.attr({
@@ -4291,10 +4316,8 @@ var Chartist = {
});
// If this is a donut, we add the stroke-width as style attribute
- if(options.donut) {
- pathElement.attr({
- 'style': 'stroke-width: ' + donutWidth.value + 'px'
- });
+ if(options.donut && !options.donutSolid) {
+ pathElement._node.style.strokeWidth = donutWidth.value + 'px';
}
// Fire off draw event
diff --git a/contao/assets/chartist/dist/chartist.min.css b/contao/assets/chartist/dist/chartist.min.css
index 9f9b908..6a23d47 100644
--- a/contao/assets/chartist/dist/chartist.min.css
+++ b/contao/assets/chartist/dist/chartist.min.css
@@ -1 +1 @@
-.ct-double-octave:after,.ct-major-eleventh:after,.ct-major-second:after,.ct-major-seventh:after,.ct-major-sixth:after,.ct-major-tenth:after,.ct-major-third:after,.ct-major-twelfth:after,.ct-minor-second:after,.ct-minor-seventh:after,.ct-minor-sixth:after,.ct-minor-third:after,.ct-octave:after,.ct-perfect-fifth:after,.ct-perfect-fourth:after,.ct-square:after{content:"";clear:both}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-grid-background,.ct-line{fill:none}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{stroke-width:4px}.ct-area{stroke:none;fill-opacity:.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{display:table}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{display:table}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{display:table}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{display:table}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{display:table}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{display:table}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{display:table}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{display:table}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{content:"";display:table;clear:both}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{display:table}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{display:table}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{display:table}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{display:table}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{display:table}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{display:table}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{display:table}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{display:table}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0}
\ No newline at end of file
+.ct-double-octave:after,.ct-major-eleventh:after,.ct-major-second:after,.ct-major-seventh:after,.ct-major-sixth:after,.ct-major-tenth:after,.ct-major-third:after,.ct-major-twelfth:after,.ct-minor-second:after,.ct-minor-seventh:after,.ct-minor-sixth:after,.ct-minor-third:after,.ct-octave:after,.ct-perfect-fifth:after,.ct-perfect-fourth:after,.ct-square:after{content:"";clear:both}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-grid-background,.ct-line{fill:none}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{stroke-width:4px}.ct-area{stroke:none;fill-opacity:.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{display:table}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{display:table}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{display:table}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{display:table}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{display:table}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{display:table}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{display:table}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{display:table}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{content:"";display:table;clear:both}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{display:table}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{display:table}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{display:table}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{display:table}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{display:table}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{display:table}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{display:table}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{display:table}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0}
\ No newline at end of file
diff --git a/contao/assets/chartist/dist/chartist.min.js b/contao/assets/chartist/dist/chartist.min.js
index e0fec43..b54d35a 100644
--- a/contao/assets/chartist/dist/chartist.min.js
+++ b/contao/assets/chartist/dist/chartist.min.js
@@ -1,10 +1,10 @@
-/* Chartist.js 0.10.0
- * Copyright © 2016 Gion Kunz
+/* Chartist.js 0.11.0
+ * Copyright © 2017 Gion Kunz
* Free to use under either the WTFPL license or the MIT license.
* https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL
* https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT
*/
-!function(a,b){"function"==typeof define&&define.amd?define("Chartist",[],function(){return a.Chartist=b()}):"object"==typeof exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.10.0"};return function(a,b,c){"use strict";c.namespaces={svg:"http://www.w3.org/2000/svg",xmlns:"http://www.w3.org/2000/xmlns/",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",ct:"http://gionkunz.github.com/chartist-js/ct"},c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){var b,d,e;for(a=a||{},b=1;b":">",'"':""","'":"'"},c.serialize=function(a){return null===a||void 0===a?a:("number"==typeof a?a=""+a:"object"==typeof a&&(a=JSON.stringify({data:a})),Object.keys(c.escapingMap).reduce(function(a,b){return c.replaceAll(a,b,c.escapingMap[b])},a))},c.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(c.escapingMap).reduce(function(a,b){return c.replaceAll(a,c.escapingMap[b],b)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(b){}return a},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(c.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e).attr({style:"width: "+b+"; height: "+d+";"}),a.appendChild(f._node),f},c.normalizeData=function(a,b,d){var e,f={raw:a,normalized:{}};return f.normalized.series=c.getDataArray({series:a.series||[]},b,d),e=f.normalized.series.every(function(a){return a instanceof Array})?Math.max.apply(null,f.normalized.series.map(function(a){return a.length})):f.normalized.series.length,f.normalized.labels=(a.labels||[]).slice(),Array.prototype.push.apply(f.normalized.labels,c.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),b&&c.reverseData(f.normalized),f},c.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},c.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},c.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&c0?f.low=0:(f.high=1,f.low=0)),f},c.isNumeric=function(a){return null!==a&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return c.isNumeric(a)?+a:void 0},c.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},c.getMultiValue=function(a,b){return c.isMultiValue(a)?c.getNumberOrUndefined(a[b||"y"]):c.getNumberOrUndefined(a)},c.rho=function(a){function b(a,c){return a%c===0?c:b(c,a%c)}function c(a){return a*a+1}if(1===a)return a;var d,e=2,f=2;if(a%2===0)return 2;do e=c(e)%a,f=c(c(f))%a,d=b(Math.abs(e-f),a);while(1===d);return d},c.getBounds=function(a,b,d,e){function f(a,b){return a===(a+=b)&&(a*=1+(b>0?o:-o)),a}var g,h,i,j=0,k={high:b.high,low:b.low};k.valueRange=k.high-k.low,k.oom=c.orderOfMagnitude(k.valueRange),k.step=Math.pow(10,k.oom),k.min=Math.floor(k.low/k.step)*k.step,k.max=Math.ceil(k.high/k.step)*k.step,k.range=k.max-k.min,k.numberOfSteps=Math.round(k.range/k.step);var l=c.projectLength(a,k.step,k),m=l=d)k.step=1;else if(e&&n=d)k.step=n;else for(;;){if(m&&c.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(c.projectLength(a,k.step/2,k)>=d))break;if(k.step/=2,e&&k.step%1!==0){k.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var o=2.221e-16;for(k.step=Math.max(k.step,o),h=k.min,i=k.max;h+k.step<=k.low;)h=f(h,k.step);for(;i-k.step>=k.high;)i=f(i,-k.step);k.min=h,k.max=i,k.range=k.max-k.min;var p=[];for(g=k.min;g<=k.max;g=f(g,k.step)){var q=c.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},c.polarToCartesian=function(a,b,c,d){var e=(d-90)*Math.PI/180;return{x:a+c*Math.cos(e),y:b+c*Math.sin(e)}},c.createChartRect=function(a,b,d){var e=!(!b.axisX&&!b.axisY),f=e?b.axisY.offset:0,g=e?b.axisX.offset:0,h=a.width()||c.quantity(b.width).value||0,i=a.height()||c.quantity(b.height).value||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,f+j.left+j.right),i=Math.max(i,g+j.top+j.bottom);var k={padding:j,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}};return e?("start"===b.axisX.position?(k.y2=j.top+g,k.y1=Math.max(i-j.bottom,k.y2+1)):(k.y2=j.top,k.y1=Math.max(i-j.bottom-g,k.y2+1)),"start"===b.axisY.position?(k.x1=j.left+f,k.x2=Math.max(h-j.right,k.x1+1)):(k.x1=j.left,k.x2=Math.max(h-j.right-f,k.x1+1))):(k.x1=j.left,k.x2=Math.max(h-j.right,k.x1+1),k.y2=j.top,k.y1=Math.max(i-j.bottom,k.y2+1)),k},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a,j[d.units.pos+"2"]=a,j[d.counterUnits.pos+"1"]=e,j[d.counterUnits.pos+"2"]=e+f;var k=g.elem("line",j,h.join(" "));i.emit("draw",c.extend({type:"grid",axis:d,index:b,group:g,element:k},j))},c.createGridBackground=function(a,b,c,d){var e=a.elem("rect",{x:b.x1,y:b.y2,width:b.width(),height:b.height()},c,!0);d.emit("draw",{type:"gridBackground",group:a,element:e})},c.createLabel=function(a,b,d,e,f,g,h,i,j,k,l){var m,n={};if(n[f.units.pos]=a+h[f.units.pos],n[f.counterUnits.pos]=h[f.counterUnits.pos],n[f.units.len]=b,n[f.counterUnits.len]=Math.max(0,g-10),k){var o=''+e[d]+" ";m=i.foreignObject(o,c.extend({style:"overflow: visible;"},n))}else m=i.elem("text",n,j.join(" ")).text(e[d]);l.emit("draw",c.extend({type:"label",axis:f,index:d,group:i,element:m,text:e[d]},n))},c.getSeriesOption=function(a,b,c){if(a.name&&b.series&&b.series[a.name]){var d=b.series[a.name];return d.hasOwnProperty(c)?d[c]:b[c]}return b[c]},c.optionsProvider=function(b,d,e){function f(b){var f=h;if(h=c.extend({},j),d)for(i=0;i=2&&a[h]<=a[h-2]&&(g=!0),g&&(f.push({pathCoordinates:[],valueData:[]}),g=!1),f[f.length-1].pathCoordinates.push(a[h],a[h+1]),f[f.length-1].valueData.push(b[h/2]));return f}}(window,document,a),function(a,b,c){"use strict";c.Interpolation={},c.Interpolation.none=function(a){var b={fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=0;g1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(b=h[0].pathCoordinates,g=h[0].valueData,b.length<=4)return c.Interpolation.none()(b,g);for(var j,k=(new c.Svg.Path).move(b[0],b[1],!1,g[0]),l=0,m=b.length;m-2*!j>l;l+=2){var n=[{x:+b[l-2],y:+b[l-1]},{x:+b[l],y:+b[l+1]},{x:+b[l+2],y:+b[l+3]},{x:+b[l+4],y:+b[l+5]}];j?l?m-4===l?n[3]={x:+b[0],y:+b[1]}:m-2===l&&(n[2]={x:+b[0],y:+b[1]},n[3]={x:+b[2],y:+b[3]}):n[0]={x:+b[m-2],y:+b[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+b[l],y:+b[l+1]}),k.curve(d*(-n[0].x+6*n[1].x+n[2].x)/6+e*n[2].x,d*(-n[0].y+6*n[1].y+n[2].y)/6+e*n[2].y,d*(n[1].x+6*n[2].x-n[3].x)/6+e*n[2].x,d*(n[1].y+6*n[2].y-n[3].y)/6+e*n[2].y,n[2].x,n[2].y,!1,g[(l+2)/2])}return k}return c.Interpolation.none()([])}},c.Interpolation.monotoneCubic=function(a){var b={fillHoles:!1};return a=c.extend({},b,a),function d(b,e){var f=c.splitIntoSegments(b,e,{fillHoles:a.fillHoles,increasingX:!0});if(f.length){if(f.length>1){var g=[];return f.forEach(function(a){g.push(d(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(g)}if(b=f[0].pathCoordinates,e=f[0].valueData,b.length<=4)return c.Interpolation.none()(b,e);var h,i,j=[],k=[],l=b.length/2,m=[],n=[],o=[],p=[];for(h=0;h0!=n[h]>0?m[h]=0:(m[h]=3*(p[h-1]+p[h])/((2*p[h]+p[h-1])/n[h-1]+(p[h]+2*p[h-1])/n[h]),isFinite(m[h])||(m[h]=0));for(i=(new c.Svg.Path).move(j[0],k[0],!1,e[0]),h=0;h1}).map(function(a){var b=a.pathElements[0],c=a.pathElements[a.pathElements.length-1];return a.clone(!0).position(0).remove(1).move(b.x,r).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,r)}).forEach(function(c){var h=i.elem("path",{d:c.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:b.normalized.series[g],path:c.clone(),series:f,seriesIndex:g,axisX:d,axisY:e,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:e.bounds,chartRect:j,axisX:d,axisY:e,svg:this.svg,options:a})}function e(a,b,d,e){c.Line["super"].constructor.call(this,a,b,f,c.extend({},f,d),e)}var f={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,type:void 0,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,showLine:!0,showPoint:!0,showArea:!1,areaBase:0,lineSmooth:!0,showGridBackground:!1,low:void 0,high:void 0,chartPadding:{top:15,right:15,bottom:5,left:10},fullWidth:!1,reverseData:!1,classNames:{chart:"ct-chart-line",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",line:"ct-line",point:"ct-point",area:"ct-area",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}};c.Line=c.Base.extend({constructor:e,createChart:d})}(window,document,a),function(a,b,c){"use strict";function d(a){var b,d;a.distributeSeries?(b=c.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),b.normalized.series=b.normalized.series.map(function(a){return[a]})):b=c.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var e=this.svg.elem("g").addClass(a.classNames.gridGroup),g=this.svg.elem("g"),h=this.svg.elem("g").addClass(a.classNames.labelGroup);if(a.stackBars&&0!==b.normalized.series.length){var i=c.serialMap(b.normalized.series,function(){return Array.prototype.slice.call(arguments).map(function(a){
-return a}).reduce(function(a,b){return{x:a.x+(b&&b.x)||0,y:a.y+(b&&b.y)||0}},{x:0,y:0})});d=c.getHighLow([i],a,a.horizontalBars?"x":"y")}else d=c.getHighLow(b.normalized.series,a,a.horizontalBars?"x":"y");d.high=+a.high||(0===a.high?0:d.high),d.low=+a.low||(0===a.low?0:d.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?b.normalized.labels.slice(0,1):b.normalized.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,b.normalized.series,o,c.extend({},a.axisX,{highLow:d,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,b.normalized.series,o,c.extend({},a.axisX,{highLow:d,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,b.normalized.series,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,b.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,b.normalized.series,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,b.normalized.series,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,b.normalized.series,o,c.extend({},a.axisY,{highLow:d,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,b.normalized.series,o,c.extend({},a.axisY,{highLow:d,referenceValue:0})));var p=a.horizontalBars?o.x1+j.projectValue(0):o.y1-j.projectValue(0),q=[];l.createGridAndLabels(e,h,this.supportsForeignObject,a,this.eventEmitter),j.createGridAndLabels(e,h,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&c.createGridBackground(e,o,a.classNames.gridBackground,this.eventEmitter),b.raw.series.forEach(function(d,e){var f,h,i=e-(b.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/b.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/b.normalized.series[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":d.name,"ct:meta":c.serialize(d.meta)}),h.addClass([a.classNames.series,d.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),b.normalized.series[e].forEach(function(g,k){var r,s,t,u;if(u=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,r=a.horizontalBars?{x:o.x1+j.projectValue(g&&g.x?g.x:0,k,b.normalized.series[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,b.normalized.series[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,b.normalized.series[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,b.normalized.series[e])},l instanceof c.StepAxis&&(l.options.stretch||(r[l.units.pos]+=f*(a.horizontalBars?-1:1)),r[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1)),t=q[k]||p,q[k]=t-(p-r[l.counterUnits.pos]),void 0!==g){var v={};v[l.units.pos+"1"]=r[l.units.pos],v[l.units.pos+"2"]=r[l.units.pos],!a.stackBars||"accumulate"!==a.stackMode&&a.stackMode?(v[l.counterUnits.pos+"1"]=p,v[l.counterUnits.pos+"2"]=r[l.counterUnits.pos]):(v[l.counterUnits.pos+"1"]=t,v[l.counterUnits.pos+"2"]=q[k]),v.x1=Math.min(Math.max(v.x1,o.x1),o.x2),v.x2=Math.min(Math.max(v.x2,o.x1),o.x2),v.y1=Math.min(Math.max(v.y1,o.y2),o.y1),v.y2=Math.min(Math.max(v.y2,o.y2),o.y1);var w=c.getMetaData(d,k);s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNumeric).join(","),"ct:meta":c.serialize(w)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:w,series:d,seriesIndex:e,axisX:m,axisY:n,chartRect:o,group:h,element:s},v))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:j.bounds,chartRect:o,axisX:m,axisY:n,svg:this.svg,options:a})}function e(a,b,d,e){c.Bar["super"].constructor.call(this,a,b,f,c.extend({},f,d),e)}var f={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,high:void 0,low:void 0,referenceValue:0,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!1,showGridBackground:!1,classNames:{chart:"ct-chart-bar",horizontalBars:"ct-horizontal-bars",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",bar:"ct-bar",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}};c.Bar=c.Base.extend({constructor:e,createChart:d})}(window,document,a),function(a,b,c){"use strict";function d(a,b,c){var d=b.x>a.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,h,i,j=c.normalizeData(this.data),k=[],l=a.startAngle;this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),e=c.createChartRect(this.svg,a,g.padding),f=Math.min(e.width()/2,e.height()/2),i=a.total||j.normalized.series.reduce(function(a,b){return a+b},0);var m=c.quantity(a.donutWidth);"%"===m.unit&&(m.value*=f/100),f-=a.donut?m.value/2:0,h="outside"===a.labelPosition||a.donut?f:"center"===a.labelPosition?0:f/2,h+=a.labelOffset;var n={x:e.x1+e.width()/2,y:e.y2+e.height()/2},o=1===j.raw.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;j.raw.series.forEach(function(a,b){k[b]=this.svg.elem("g",null,null)}.bind(this)),a.showLabel&&(b=this.svg.elem("g",null,null)),j.raw.series.forEach(function(e,g){if(0!==j.normalized.series[g]||!a.ignoreEmptyValues){k[g].attr({"ct:series-name":e.name}),k[g].addClass([a.classNames.series,e.className||a.classNames.series+"-"+c.alphaNumerate(g)].join(" "));var p=i>0?l+j.normalized.series[g]/i*360:0,q=Math.max(0,l-(0===g||o?0:.2));p-q>=359.99&&(p=q+359.99);var r=c.polarToCartesian(n.x,n.y,f,q),s=c.polarToCartesian(n.x,n.y,f,p),t=new c.Svg.Path((!a.donut)).move(s.x,s.y).arc(f,f,0,p-l>180,0,r.x,r.y);a.donut||t.line(n.x,n.y);var u=k[g].elem("path",{d:t.stringify()},a.donut?a.classNames.sliceDonut:a.classNames.slicePie);if(u.attr({"ct:value":j.normalized.series[g],"ct:meta":c.serialize(e.meta)}),a.donut&&u.attr({style:"stroke-width: "+m.value+"px"}),this.eventEmitter.emit("draw",{type:"slice",value:j.normalized.series[g],totalDataSum:i,index:g,meta:e.meta,series:e,group:k[g],element:u,path:t.clone(),center:n,radius:f,startAngle:l,endAngle:p}),a.showLabel){var v;v=1===j.raw.series.length?{x:n.x,y:n.y}:c.polarToCartesian(n.x,n.y,h,l+(p-l)/2);var w;w=j.normalized.labels&&!c.isFalseyButZero(j.normalized.labels[g])?j.normalized.labels[g]:j.normalized.series[g];var x=a.labelInterpolationFnc(w,g);if(x||0===x){var y=b.elem("text",{dx:v.x,dy:v.y,"text-anchor":d(n,v,a.labelDirection)},a.classNames.label).text(""+x);this.eventEmitter.emit("draw",{type:"label",index:g,group:b,element:y,text:""+x,x:v.x,y:v.y})}}l=p}}.bind(this)),this.eventEmitter.emit("created",{chartRect:e,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie["super"].constructor.call(this,a,b,g,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chartPie:"ct-chart-pie",chartDonut:"ct-chart-donut",series:"ct-series",slicePie:"ct-slice-pie",sliceDonut:"ct-slice-donut",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelPosition:"inside",labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a});
+!function(a,b){"function"==typeof define&&define.amd?define("Chartist",[],function(){return a.Chartist=b()}):"object"==typeof module&&module.exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.11.0"};return function(a,b,c){"use strict";c.namespaces={svg:"http://www.w3.org/2000/svg",xmlns:"http://www.w3.org/2000/xmlns/",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",ct:"http://gionkunz.github.com/chartist-js/ct"},c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){var b,d,e;for(a=a||{},b=1;b":">",'"':""","'":"'"},c.serialize=function(a){return null===a||void 0===a?a:("number"==typeof a?a=""+a:"object"==typeof a&&(a=JSON.stringify({data:a})),Object.keys(c.escapingMap).reduce(function(a,b){return c.replaceAll(a,b,c.escapingMap[b])},a))},c.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(c.escapingMap).reduce(function(a,b){return c.replaceAll(a,c.escapingMap[b],b)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(b){}return a},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(c.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e),f._node.style.width=b,f._node.style.height=d,a.appendChild(f._node),f},c.normalizeData=function(a,b,d){var e,f={raw:a,normalized:{}};return f.normalized.series=c.getDataArray({series:a.series||[]},b,d),e=f.normalized.series.every(function(a){return a instanceof Array})?Math.max.apply(null,f.normalized.series.map(function(a){return a.length})):f.normalized.series.length,f.normalized.labels=(a.labels||[]).slice(),Array.prototype.push.apply(f.normalized.labels,c.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),b&&c.reverseData(f.normalized),f},c.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},c.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},c.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&c0?f.low=0:(f.high=1,f.low=0)),f},c.isNumeric=function(a){return null!==a&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return c.isNumeric(a)?+a:void 0},c.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},c.getMultiValue=function(a,b){return c.isMultiValue(a)?c.getNumberOrUndefined(a[b||"y"]):c.getNumberOrUndefined(a)},c.rho=function(a){function b(a,c){return a%c===0?c:b(c,a%c)}function c(a){return a*a+1}if(1===a)return a;var d,e=2,f=2;if(a%2===0)return 2;do e=c(e)%a,f=c(c(f))%a,d=b(Math.abs(e-f),a);while(1===d);return d},c.getBounds=function(a,b,d,e){function f(a,b){return a===(a+=b)&&(a*=1+(b>0?o:-o)),a}var g,h,i,j=0,k={high:b.high,low:b.low};k.valueRange=k.high-k.low,k.oom=c.orderOfMagnitude(k.valueRange),k.step=Math.pow(10,k.oom),k.min=Math.floor(k.low/k.step)*k.step,k.max=Math.ceil(k.high/k.step)*k.step,k.range=k.max-k.min,k.numberOfSteps=Math.round(k.range/k.step);var l=c.projectLength(a,k.step,k),m=l=d)k.step=1;else if(e&&n=d)k.step=n;else for(;;){if(m&&c.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(c.projectLength(a,k.step/2,k)>=d))break;if(k.step/=2,e&&k.step%1!==0){k.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var o=2.221e-16;for(k.step=Math.max(k.step,o),h=k.min,i=k.max;h+k.step<=k.low;)h=f(h,k.step);for(;i-k.step>=k.high;)i=f(i,-k.step);k.min=h,k.max=i,k.range=k.max-k.min;var p=[];for(g=k.min;g<=k.max;g=f(g,k.step)){var q=c.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},c.polarToCartesian=function(a,b,c,d){var e=(d-90)*Math.PI/180;return{x:a+c*Math.cos(e),y:b+c*Math.sin(e)}},c.createChartRect=function(a,b,d){var e=!(!b.axisX&&!b.axisY),f=e?b.axisY.offset:0,g=e?b.axisX.offset:0,h=a.width()||c.quantity(b.width).value||0,i=a.height()||c.quantity(b.height).value||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,f+j.left+j.right),i=Math.max(i,g+j.top+j.bottom);var k={padding:j,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}};return e?("start"===b.axisX.position?(k.y2=j.top+g,k.y1=Math.max(i-j.bottom,k.y2+1)):(k.y2=j.top,k.y1=Math.max(i-j.bottom-g,k.y2+1)),"start"===b.axisY.position?(k.x1=j.left+f,k.x2=Math.max(h-j.right,k.x1+1)):(k.x1=j.left,k.x2=Math.max(h-j.right-f,k.x1+1))):(k.x1=j.left,k.x2=Math.max(h-j.right,k.x1+1),k.y2=j.top,k.y1=Math.max(i-j.bottom,k.y2+1)),k},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a,j[d.units.pos+"2"]=a,j[d.counterUnits.pos+"1"]=e,j[d.counterUnits.pos+"2"]=e+f;var k=g.elem("line",j,h.join(" "));i.emit("draw",c.extend({type:"grid",axis:d,index:b,group:g,element:k},j))},c.createGridBackground=function(a,b,c,d){var e=a.elem("rect",{x:b.x1,y:b.y2,width:b.width(),height:b.height()},c,!0);d.emit("draw",{type:"gridBackground",group:a,element:e})},c.createLabel=function(a,d,e,f,g,h,i,j,k,l,m){var n,o={};if(o[g.units.pos]=a+i[g.units.pos],o[g.counterUnits.pos]=i[g.counterUnits.pos],o[g.units.len]=d,o[g.counterUnits.len]=Math.max(0,h-10),l){var p=b.createElement("span");p.className=k.join(" "),p.setAttribute("xmlns",c.namespaces.xhtml),p.innerText=f[e],p.style[g.units.len]=Math.round(o[g.units.len])+"px",p.style[g.counterUnits.len]=Math.round(o[g.counterUnits.len])+"px",n=j.foreignObject(p,c.extend({style:"overflow: visible;"},o))}else n=j.elem("text",o,k.join(" ")).text(f[e]);m.emit("draw",c.extend({type:"label",axis:g,index:e,group:j,element:n,text:f[e]},o))},c.getSeriesOption=function(a,b,c){if(a.name&&b.series&&b.series[a.name]){var d=b.series[a.name];return d.hasOwnProperty(c)?d[c]:b[c]}return b[c]},c.optionsProvider=function(b,d,e){function f(b){var f=h;if(h=c.extend({},j),d)for(i=0;i=2&&a[h]<=a[h-2]&&(g=!0),g&&(f.push({pathCoordinates:[],valueData:[]}),g=!1),f[f.length-1].pathCoordinates.push(a[h],a[h+1]),f[f.length-1].valueData.push(b[h/2]));return f}}(window,document,a),function(a,b,c){"use strict";c.Interpolation={},c.Interpolation.none=function(a){var b={fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=0;g1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(b=h[0].pathCoordinates,g=h[0].valueData,b.length<=4)return c.Interpolation.none()(b,g);for(var j,k=(new c.Svg.Path).move(b[0],b[1],!1,g[0]),l=0,m=b.length;m-2*!j>l;l+=2){var n=[{x:+b[l-2],y:+b[l-1]},{x:+b[l],y:+b[l+1]},{x:+b[l+2],y:+b[l+3]},{x:+b[l+4],y:+b[l+5]}];j?l?m-4===l?n[3]={x:+b[0],y:+b[1]}:m-2===l&&(n[2]={x:+b[0],y:+b[1]},n[3]={x:+b[2],y:+b[3]}):n[0]={x:+b[m-2],y:+b[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+b[l],y:+b[l+1]}),k.curve(d*(-n[0].x+6*n[1].x+n[2].x)/6+e*n[2].x,d*(-n[0].y+6*n[1].y+n[2].y)/6+e*n[2].y,d*(n[1].x+6*n[2].x-n[3].x)/6+e*n[2].x,d*(n[1].y+6*n[2].y-n[3].y)/6+e*n[2].y,n[2].x,n[2].y,!1,g[(l+2)/2])}return k}return c.Interpolation.none()([])}},c.Interpolation.monotoneCubic=function(a){var b={fillHoles:!1};return a=c.extend({},b,a),function d(b,e){var f=c.splitIntoSegments(b,e,{fillHoles:a.fillHoles,increasingX:!0});if(f.length){if(f.length>1){var g=[];return f.forEach(function(a){g.push(d(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(g)}if(b=f[0].pathCoordinates,e=f[0].valueData,b.length<=4)return c.Interpolation.none()(b,e);var h,i,j=[],k=[],l=b.length/2,m=[],n=[],o=[],p=[];for(h=0;h0!=n[h]>0?m[h]=0:(m[h]=3*(p[h-1]+p[h])/((2*p[h]+p[h-1])/n[h-1]+(p[h]+2*p[h-1])/n[h]),isFinite(m[h])||(m[h]=0));for(i=(new c.Svg.Path).move(j[0],k[0],!1,e[0]),h=0;h1}).map(function(a){var b=a.pathElements[0],c=a.pathElements[a.pathElements.length-1];return a.clone(!0).position(0).remove(1).move(b.x,r).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,r)}).forEach(function(c){var h=i.elem("path",{d:c.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:b.normalized.series[g],path:c.clone(),series:f,seriesIndex:g,axisX:d,axisY:e,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:e.bounds,chartRect:j,axisX:d,axisY:e,svg:this.svg,options:a})}function e(a,b,d,e){c.Line["super"].constructor.call(this,a,b,f,c.extend({},f,d),e)}var f={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,type:void 0,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,showLine:!0,showPoint:!0,showArea:!1,areaBase:0,lineSmooth:!0,showGridBackground:!1,low:void 0,high:void 0,chartPadding:{top:15,right:15,bottom:5,left:10},fullWidth:!1,reverseData:!1,classNames:{chart:"ct-chart-line",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",line:"ct-line",point:"ct-point",area:"ct-area",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}};c.Line=c.Base.extend({constructor:e,createChart:d})}(window,document,a),function(a,b,c){"use strict";function d(a){var b,d;a.distributeSeries?(b=c.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),b.normalized.series=b.normalized.series.map(function(a){return[a]})):b=c.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var e=this.svg.elem("g").addClass(a.classNames.gridGroup),g=this.svg.elem("g"),h=this.svg.elem("g").addClass(a.classNames.labelGroup);if(a.stackBars&&0!==b.normalized.series.length){var i=c.serialMap(b.normalized.series,function(){
+return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+(b&&b.x)||0,y:a.y+(b&&b.y)||0}},{x:0,y:0})});d=c.getHighLow([i],a,a.horizontalBars?"x":"y")}else d=c.getHighLow(b.normalized.series,a,a.horizontalBars?"x":"y");d.high=+a.high||(0===a.high?0:d.high),d.low=+a.low||(0===a.low?0:d.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?b.normalized.labels.slice(0,1):b.normalized.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,b.normalized.series,o,c.extend({},a.axisX,{highLow:d,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,b.normalized.series,o,c.extend({},a.axisX,{highLow:d,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,b.normalized.series,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,b.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,b.normalized.series,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,b.normalized.series,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,b.normalized.series,o,c.extend({},a.axisY,{highLow:d,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,b.normalized.series,o,c.extend({},a.axisY,{highLow:d,referenceValue:0})));var p=a.horizontalBars?o.x1+j.projectValue(0):o.y1-j.projectValue(0),q=[];l.createGridAndLabels(e,h,this.supportsForeignObject,a,this.eventEmitter),j.createGridAndLabels(e,h,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&c.createGridBackground(e,o,a.classNames.gridBackground,this.eventEmitter),b.raw.series.forEach(function(d,e){var f,h,i=e-(b.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/b.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/b.normalized.series[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":d.name,"ct:meta":c.serialize(d.meta)}),h.addClass([a.classNames.series,d.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),b.normalized.series[e].forEach(function(g,k){var r,s,t,u;if(u=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,r=a.horizontalBars?{x:o.x1+j.projectValue(g&&g.x?g.x:0,k,b.normalized.series[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,b.normalized.series[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,b.normalized.series[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,b.normalized.series[e])},l instanceof c.StepAxis&&(l.options.stretch||(r[l.units.pos]+=f*(a.horizontalBars?-1:1)),r[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1)),t=q[k]||p,q[k]=t-(p-r[l.counterUnits.pos]),void 0!==g){var v={};v[l.units.pos+"1"]=r[l.units.pos],v[l.units.pos+"2"]=r[l.units.pos],!a.stackBars||"accumulate"!==a.stackMode&&a.stackMode?(v[l.counterUnits.pos+"1"]=p,v[l.counterUnits.pos+"2"]=r[l.counterUnits.pos]):(v[l.counterUnits.pos+"1"]=t,v[l.counterUnits.pos+"2"]=q[k]),v.x1=Math.min(Math.max(v.x1,o.x1),o.x2),v.x2=Math.min(Math.max(v.x2,o.x1),o.x2),v.y1=Math.min(Math.max(v.y1,o.y2),o.y1),v.y2=Math.min(Math.max(v.y2,o.y2),o.y1);var w=c.getMetaData(d,k);s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNumeric).join(","),"ct:meta":c.serialize(w)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:w,series:d,seriesIndex:e,axisX:m,axisY:n,chartRect:o,group:h,element:s},v))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:j.bounds,chartRect:o,axisX:m,axisY:n,svg:this.svg,options:a})}function e(a,b,d,e){c.Bar["super"].constructor.call(this,a,b,f,c.extend({},f,d),e)}var f={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,high:void 0,low:void 0,referenceValue:0,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!1,showGridBackground:!1,classNames:{chart:"ct-chart-bar",horizontalBars:"ct-horizontal-bars",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",bar:"ct-bar",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}};c.Bar=c.Base.extend({constructor:e,createChart:d})}(window,document,a),function(a,b,c){"use strict";function d(a,b,c){var d=b.x>a.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,h,i,j=c.normalizeData(this.data),k=[],l=a.startAngle;this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),e=c.createChartRect(this.svg,a,g.padding),f=Math.min(e.width()/2,e.height()/2),i=a.total||j.normalized.series.reduce(function(a,b){return a+b},0);var m=c.quantity(a.donutWidth);"%"===m.unit&&(m.value*=f/100),f-=a.donut&&!a.donutSolid?m.value/2:0,h="outside"===a.labelPosition||a.donut&&!a.donutSolid?f:"center"===a.labelPosition?0:a.donutSolid?f-m.value/2:f/2,h+=a.labelOffset;var n={x:e.x1+e.width()/2,y:e.y2+e.height()/2},o=1===j.raw.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;j.raw.series.forEach(function(a,b){k[b]=this.svg.elem("g",null,null)}.bind(this)),a.showLabel&&(b=this.svg.elem("g",null,null)),j.raw.series.forEach(function(e,g){if(0!==j.normalized.series[g]||!a.ignoreEmptyValues){k[g].attr({"ct:series-name":e.name}),k[g].addClass([a.classNames.series,e.className||a.classNames.series+"-"+c.alphaNumerate(g)].join(" "));var p=i>0?l+j.normalized.series[g]/i*360:0,q=Math.max(0,l-(0===g||o?0:.2));p-q>=359.99&&(p=q+359.99);var r,s,t,u=c.polarToCartesian(n.x,n.y,f,q),v=c.polarToCartesian(n.x,n.y,f,p),w=new c.Svg.Path(!a.donut||a.donutSolid).move(v.x,v.y).arc(f,f,0,p-l>180,0,u.x,u.y);a.donut?a.donutSolid&&(t=f-m.value,r=c.polarToCartesian(n.x,n.y,t,l-(0===g||o?0:.2)),s=c.polarToCartesian(n.x,n.y,t,p),w.line(r.x,r.y),w.arc(t,t,0,p-l>180,1,s.x,s.y)):w.line(n.x,n.y);var x=a.classNames.slicePie;a.donut&&(x=a.classNames.sliceDonut,a.donutSolid&&(x=a.classNames.sliceDonutSolid));var y=k[g].elem("path",{d:w.stringify()},x);if(y.attr({"ct:value":j.normalized.series[g],"ct:meta":c.serialize(e.meta)}),a.donut&&!a.donutSolid&&(y._node.style.strokeWidth=m.value+"px"),this.eventEmitter.emit("draw",{type:"slice",value:j.normalized.series[g],totalDataSum:i,index:g,meta:e.meta,series:e,group:k[g],element:y,path:w.clone(),center:n,radius:f,startAngle:l,endAngle:p}),a.showLabel){var z;z=1===j.raw.series.length?{x:n.x,y:n.y}:c.polarToCartesian(n.x,n.y,h,l+(p-l)/2);var A;A=j.normalized.labels&&!c.isFalseyButZero(j.normalized.labels[g])?j.normalized.labels[g]:j.normalized.series[g];var B=a.labelInterpolationFnc(A,g);if(B||0===B){var C=b.elem("text",{dx:z.x,dy:z.y,"text-anchor":d(n,z,a.labelDirection)},a.classNames.label).text(""+B);this.eventEmitter.emit("draw",{type:"label",index:g,group:b,element:C,text:""+B,x:z.x,y:z.y})}}l=p}}.bind(this)),this.eventEmitter.emit("created",{chartRect:e,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie["super"].constructor.call(this,a,b,g,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chartPie:"ct-chart-pie",chartDonut:"ct-chart-donut",series:"ct-series",slicePie:"ct-slice-pie",sliceDonut:"ct-slice-donut",sliceDonutSolid:"ct-slice-donut-solid",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutSolid:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelPosition:"inside",labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a});
//# sourceMappingURL=chartist.min.js.map
\ No newline at end of file
diff --git a/contao/assets/chartist/dist/chartist.min.js.map b/contao/assets/chartist/dist/chartist.min.js.map
index 7006d74..bdcce04 100644
--- a/contao/assets/chartist/dist/chartist.min.js.map
+++ b/contao/assets/chartist/dist/chartist.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["chartist.js"],"names":["root","factory","define","amd","exports","module","this","Chartist","version","window","document","namespaces","svg","xmlns","xhtml","xlink","ct","noop","n","alphaNumerate","String","fromCharCode","extend","target","i","source","sourceProp","arguments","length","prop","Array","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","forEach","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","prototype","slice","call","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","style","appendChild","_node","normalizeData","reverse","multi","labelCount","output","raw","normalized","series","getDataArray","every","labels","push","reverseData","safeHasProperty","object","property","hasOwnProperty","isDataHoleValue","isNaN","recursiveConvert","multiValue","getNumberOrUndefined","y","x","normalizePadding","padding","fallback","top","right","bottom","left","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","dimension","recursiveHighLow","findHigh","highLow","high","findLow","low","toUpperCase","Number","MAX_VALUE","referenceValue","min","isNumeric","isFinite","isFalseyButZero","isMultiValue","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","safeIncrement","increment","EPSILON","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","sin","createChartRect","fallbackPadding","hasAxis","axisY","yAxisOffset","xAxisOffset","normalizedPadding","chartRect","y1","y2","position","createGrid","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createGridBackground","gridGroup","gridBackground","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","mediaEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","splitIntoSegments","pathCoordinates","valueData","defaultOptions","increasingX","fillHoles","segments","hole","Interpolation","none","path","Path","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","tension","t","c","paths","segment","z","iLen","monotoneCubic","xs","ys","ms","ds","dys","dxs","postpone","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","override","initializeTimeoutId","createChart","detach","clearTimeout","removeEventListener","resizeListener","on","off","initialize","addEventListener","bind","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","setTimeout","attributes","parent","insertFirst","Element","createElementNS","xmlns:ct","firstChild","insertBefore","ns","getAttribute","namespacedAttribute","split","setAttributeNS","setAttribute","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","getNode","createElement","innerHTML","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","names","concat","self","removeClass","removedClasses","removeAllClasses","getBoundingClientRect","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","err","to","params","SvgList","nodeList","svgElements","prototypeProperty","feature","implementation","hasFeature","easingCubicBeziers","easeInSine","easeOutSine","easeInOutSine","easeInQuad","easeOutQuad","easeInOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","easeInExpo","easeOutExpo","easeInOutExpo","easeInCirc","easeOutCirc","easeInOutCirc","easeInBack","easeOutBack","easeInOutBack","command","pathElements","relative","pathElement","toLowerCase","forEachParam","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","count","arc","rx","ry","xAr","lAf","sf","chunks","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transform","transformFnc","transformed","clone","splitByCommand","joinedPath","j","m","l","a","Axis","ticks","axisUnits","rectEnd","rectStart","gridOffset","rectOffset","createGridAndLabels","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","calc","stretch","chart","seriesGroup","fullWidth","showGridBackground","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","seriesMeta","areaBaseProjected","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","prev","curr","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","stackMode","metaData","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","sliceDonut","slicePie","rawValue","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","file":"chartist.min.js","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define('Chartist', [], function () {\n return (root['Chartist'] = factory());\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like environments that support module.exports,\n // like Node.\n module.exports = factory();\n } else {\n root['Chartist'] = factory();\n }\n}(this, function () {\n\n/* Chartist.js 0.10.0\n * Copyright © 2016 Gion Kunz\n * Free to use under either the WTFPL license or the MIT license.\n * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL\n * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT\n */\n/**\n * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules.\n *\n * @module Chartist.Core\n */\nvar Chartist = {\n version: '0.10.0'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\n\n /**\n * This object contains all namespaces used within Chartist.\n *\n * @memberof Chartist.Core\n * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}}\n */\n Chartist.namespaces = {\n svg: 'http://www.w3.org/2000/svg',\n xmlns: 'http://www.w3.org/2000/xmlns/',\n xhtml: 'http://www.w3.org/1999/xhtml',\n xlink: 'http://www.w3.org/1999/xlink',\n ct: 'http://gionkunz.github.com/chartist-js/ct'\n };\n\n /**\n * Helps to simplify functional style code\n *\n * @memberof Chartist.Core\n * @param {*} n This exact value will be returned by the noop function\n * @return {*} The same value that was provided to the n parameter\n */\n Chartist.noop = function (n) {\n return n;\n };\n\n /**\n * Generates a-z from a number 0 to 26\n *\n * @memberof Chartist.Core\n * @param {Number} n A number from 0 to 26 that will result in a letter a-z\n * @return {String} A character from a-z based on the input number n\n */\n Chartist.alphaNumerate = function (n) {\n // Limit to a-z\n return String.fromCharCode(97 + n % 26);\n };\n\n /**\n * Simple recursive object extend\n *\n * @memberof Chartist.Core\n * @param {Object} target Target object where the source will be merged into\n * @param {Object...} sources This object (objects) will be merged into target and then target is returned\n * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source\n */\n Chartist.extend = function (target) {\n var i, source, sourceProp;\n target = target || {};\n\n for (i = 1; i < arguments.length; i++) {\n source = arguments[i];\n for (var prop in source) {\n sourceProp = source[prop];\n if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], sourceProp);\n } else {\n target[prop] = sourceProp;\n }\n }\n }\n\n return target;\n };\n\n /**\n * Replaces all occurrences of subStr in str with newSubStr and returns a new string.\n *\n * @memberof Chartist.Core\n * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @return {String}\n */\n Chartist.replaceAll = function(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\n };\n\n /**\n * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {Number} value\n * @param {String} unit\n * @return {String} Returns the passed number value with unit.\n */\n Chartist.ensureUnit = function(value, unit) {\n if(typeof value === 'number') {\n value = value + unit;\n }\n\n return value;\n };\n\n /**\n * Converts a number or string to a quantity object.\n *\n * @memberof Chartist.Core\n * @param {String|Number} input\n * @return {Object} Returns an object containing the value as number and the unit as string.\n */\n Chartist.quantity = function(input) {\n if (typeof input === 'string') {\n var match = (/^(\\d+)\\s*(.*)$/g).exec(input);\n return {\n value : +match[1],\n unit: match[2] || undefined\n };\n }\n return { value: input };\n };\n\n /**\n * This is a wrapper around document.querySelector that will return the query if it's already of type Node\n *\n * @memberof Chartist.Core\n * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly\n * @return {Node}\n */\n Chartist.querySelector = function(query) {\n return query instanceof Node ? query : document.querySelector(query);\n };\n\n /**\n * Functional style helper to produce array with given length initialized with undefined values\n *\n * @memberof Chartist.Core\n * @param length\n * @return {Array}\n */\n Chartist.times = function(length) {\n return Array.apply(null, new Array(length));\n };\n\n /**\n * Sum helper to be used in reduce functions\n *\n * @memberof Chartist.Core\n * @param previous\n * @param current\n * @return {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + (current ? current : 0);\n };\n\n /**\n * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor.\n *\n * @memberof Chartist.Core\n * @param {Number} factor\n * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array\n */\n Chartist.mapMultiply = function(factor) {\n return function(num) {\n return num * factor;\n };\n };\n\n /**\n * Add helper to be used in `Array.map` for adding a addend to each value of an array.\n *\n * @memberof Chartist.Core\n * @param {Number} addend\n * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array\n */\n Chartist.mapAdd = function(addend) {\n return function(num) {\n return num + addend;\n };\n };\n\n /**\n * Map for multi dimensional arrays where their nested arrays will be mapped in serial. The output array will have the length of the largest nested array. The callback function is called with variable arguments where each argument is the nested array value (or undefined if there are no more values).\n *\n * @memberof Chartist.Core\n * @param arr\n * @param cb\n * @return {Array}\n */\n Chartist.serialMap = function(arr, cb) {\n var result = [],\n length = Math.max.apply(null, arr.map(function(e) {\n return e.length;\n }));\n\n Chartist.times(length).forEach(function(e, index) {\n var args = arr.map(function(e) {\n return e[index];\n });\n\n result[index] = cb.apply(null, args);\n });\n\n return result;\n };\n\n /**\n * This helper function can be used to round values with certain precision level after decimal. This is used to prevent rounding errors near float point precision limit.\n *\n * @memberof Chartist.Core\n * @param {Number} value The value that should be rounded with precision\n * @param {Number} [digits] The number of digits after decimal used to do the rounding\n * @returns {number} Rounded value\n */\n Chartist.roundWithPrecision = function(value, digits) {\n var precision = Math.pow(10, digits || Chartist.precision);\n return Math.round(value * precision) / precision;\n };\n\n /**\n * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number.\n *\n * @memberof Chartist.Core\n * @type {number}\n */\n Chartist.precision = 8;\n\n /**\n * A map with characters to escape for strings to be safely used as attribute values.\n *\n * @memberof Chartist.Core\n * @type {Object}\n */\n Chartist.escapingMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n '\\'': '''\n };\n\n /**\n * This function serializes arbitrary data to a string. In case of data that can't be easily converted to a string, this function will create a wrapper object and serialize the data using JSON.stringify. The outcoming string will always be escaped using Chartist.escapingMap.\n * If called with null or undefined the function will return immediately with null or undefined.\n *\n * @memberof Chartist.Core\n * @param {Number|String|Object} data\n * @return {String}\n */\n Chartist.serialize = function(data) {\n if(data === null || data === undefined) {\n return data;\n } else if(typeof data === 'number') {\n data = ''+data;\n } else if(typeof data === 'object') {\n data = JSON.stringify({data: data});\n }\n\n return Object.keys(Chartist.escapingMap).reduce(function(result, key) {\n return Chartist.replaceAll(result, key, Chartist.escapingMap[key]);\n }, data);\n };\n\n /**\n * This function de-serializes a string previously serialized with Chartist.serialize. The string will always be unescaped using Chartist.escapingMap before it's returned. Based on the input value the return type can be Number, String or Object. JSON.parse is used with try / catch to see if the unescaped string can be parsed into an Object and this Object will be returned on success.\n *\n * @memberof Chartist.Core\n * @param {String} data\n * @return {String|Number|Object}\n */\n Chartist.deserialize = function(data) {\n if(typeof data !== 'string') {\n return data;\n }\n\n data = Object.keys(Chartist.escapingMap).reduce(function(result, key) {\n return Chartist.replaceAll(result, Chartist.escapingMap[key], key);\n }, data);\n\n try {\n data = JSON.parse(data);\n data = data.data !== undefined ? data.data : data;\n } catch(e) {}\n\n return data;\n };\n\n /**\n * Create or reinitialize the SVG element for the chart\n *\n * @memberof Chartist.Core\n * @param {Node} container The containing DOM Node object that will be used to plant the SVG element\n * @param {String} width Set the width of the SVG element. Default is 100%\n * @param {String} height Set the height of the SVG element. Default is 100%\n * @param {String} className Specify a class to be added to the SVG element\n * @return {Object} The created/reinitialized SVG element\n */\n Chartist.createSvg = function (container, width, height, className) {\n var svg;\n\n width = width || '100%';\n height = height || '100%';\n\n // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it\n // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/\n Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) {\n return svg.getAttributeNS(Chartist.namespaces.xmlns, 'ct');\n }).forEach(function removePreviousElement(svg) {\n container.removeChild(svg);\n });\n\n // Create svg object with width and height or use 100% as default\n svg = new Chartist.Svg('svg').attr({\n width: width,\n height: height\n }).addClass(className).attr({\n style: 'width: ' + width + '; height: ' + height + ';'\n });\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n\n return svg;\n };\n\n /**\n * Ensures that the data object passed as second argument to the charts is present and correctly initialized.\n *\n * @param {Object} data The data object that is passed as second argument to the charts\n * @return {Object} The normalized data object\n */\n Chartist.normalizeData = function(data, reverse, multi) {\n var labelCount;\n var output = {\n raw: data,\n normalized: {}\n };\n\n // Check if we should generate some labels based on existing series data\n output.normalized.series = Chartist.getDataArray({\n series: data.series || []\n }, reverse, multi);\n\n // If all elements of the normalized data array are arrays we're dealing with\n // multi series data and we need to find the largest series if they are un-even\n if (output.normalized.series.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, output.normalized.series.map(function(series) {\n return series.length;\n }));\n } else {\n // We're dealing with Pie data so we just take the normalized array length\n labelCount = output.normalized.series.length;\n }\n\n output.normalized.labels = (data.labels || []).slice();\n // Padding the labels to labelCount with empty strings\n Array.prototype.push.apply(\n output.normalized.labels,\n Chartist.times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() {\n return '';\n })\n );\n\n if(reverse) {\n Chartist.reverseData(output.normalized);\n }\n\n return output;\n };\n\n /**\n * This function safely checks if an objects has an owned property.\n *\n * @param {Object} object The object where to check for a property\n * @param {string} property The property name\n * @returns {boolean} Returns true if the object owns the specified property\n */\n Chartist.safeHasProperty = function(object, property) {\n return object !== null &&\n typeof object === 'object' &&\n object.hasOwnProperty(property);\n };\n\n /**\n * Checks if a value is considered a hole in the data series.\n *\n * @param {*} value\n * @returns {boolean} True if the value is considered a data hole\n */\n Chartist.isDataHoleValue = function(value) {\n return value === null ||\n value === undefined ||\n (typeof value === 'number' && isNaN(value));\n };\n\n /**\n * Reverses the series, labels and series data arrays.\n *\n * @memberof Chartist.Core\n * @param data\n */\n Chartist.reverseData = function(data) {\n data.labels.reverse();\n data.series.reverse();\n for (var i = 0; i < data.series.length; i++) {\n if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) {\n data.series[i].data.reverse();\n } else if(data.series[i] instanceof Array) {\n data.series[i].reverse();\n }\n }\n };\n\n /**\n * Convert data series into plain array\n *\n * @memberof Chartist.Core\n * @param {Object} data The series object that contains the data to be visualized in the chart\n * @param {Boolean} [reverse] If true the whole data is reversed by the getDataArray call. This will modify the data object passed as first parameter. The labels as well as the series order is reversed. The whole series data arrays are reversed too.\n * @param {Boolean} [multi] Create a multi dimensional array from a series data array where a value object with `x` and `y` values will be created.\n * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function(data, reverse, multi) {\n // Recursively walks through nested arrays and convert string values to numbers and objects with value properties\n // to values. Check the tests in data core -> data normalization for a detailed specification of expected values\n function recursiveConvert(value) {\n if(Chartist.safeHasProperty(value, 'value')) {\n // We are dealing with value object notation so we need to recurse on value property\n return recursiveConvert(value.value);\n } else if(Chartist.safeHasProperty(value, 'data')) {\n // We are dealing with series object notation so we need to recurse on data property\n return recursiveConvert(value.data);\n } else if(value instanceof Array) {\n // Data is of type array so we need to recurse on the series\n return value.map(recursiveConvert);\n } else if(Chartist.isDataHoleValue(value)) {\n // We're dealing with a hole in the data and therefore need to return undefined\n // We're also returning undefined for multi value output\n return undefined;\n } else {\n // We need to prepare multi value output (x and y data)\n if(multi) {\n var multiValue = {};\n\n // Single series value arrays are assumed to specify the Y-Axis value\n // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}]\n // If multi is a string then it's assumed that it specified which dimension should be filled as default\n if(typeof multi === 'string') {\n multiValue[multi] = Chartist.getNumberOrUndefined(value);\n } else {\n multiValue.y = Chartist.getNumberOrUndefined(value);\n }\n\n multiValue.x = value.hasOwnProperty('x') ? Chartist.getNumberOrUndefined(value.x) : multiValue.x;\n multiValue.y = value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : multiValue.y;\n\n return multiValue;\n\n } else {\n // We can return simple data\n return Chartist.getNumberOrUndefined(value);\n }\n }\n }\n\n return data.series.map(recursiveConvert);\n };\n\n /**\n * Converts a number into a padding object.\n *\n * @memberof Chartist.Core\n * @param {Object|Number} padding\n * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed\n * @returns {Object} Returns a padding object containing top, right, bottom, left properties filled with the padding number passed in as argument. If the argument is something else than a number (presumably already a correct padding object) then this argument is directly returned.\n */\n Chartist.normalizePadding = function(padding, fallback) {\n fallback = fallback || 0;\n\n return typeof padding === 'number' ? {\n top: padding,\n right: padding,\n bottom: padding,\n left: padding\n } : {\n top: typeof padding.top === 'number' ? padding.top : fallback,\n right: typeof padding.right === 'number' ? padding.right : fallback,\n bottom: typeof padding.bottom === 'number' ? padding.bottom : fallback,\n left: typeof padding.left === 'number' ? padding.left : fallback\n };\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? value.meta : undefined;\n };\n\n /**\n * Calculate the order of magnitude for the chart scale\n *\n * @memberof Chartist.Core\n * @param {Number} value The value Range of the chart\n * @return {Number} The order of magnitude\n */\n Chartist.orderOfMagnitude = function (value) {\n return Math.floor(Math.log(Math.abs(value)) / Math.LN10);\n };\n\n /**\n * Project a data length into screen coordinates (pixels)\n *\n * @memberof Chartist.Core\n * @param {Object} axisLength The svg element for the chart\n * @param {Number} length Single data value from a series array\n * @param {Object} bounds All the values to set the bounds of the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (axisLength, length, bounds) {\n return length / bounds.range * axisLength;\n };\n\n /**\n * Get the height of the area in the chart for the data series\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The height of the area in the chart for the data series\n */\n Chartist.getAvailableHeight = function (svg, options) {\n return Math.max((Chartist.quantity(options.height).value || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0);\n };\n\n /**\n * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart.\n *\n * @memberof Chartist.Core\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} options The Object that contains the chart options\n * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (data, options, dimension) {\n // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred\n options = Chartist.extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {});\n\n var highLow = {\n high: options.high === undefined ? -Number.MAX_VALUE : +options.high,\n low: options.low === undefined ? Number.MAX_VALUE : +options.low\n };\n var findHigh = options.high === undefined;\n var findLow = options.low === undefined;\n\n // Function to recursively walk through arrays and find highest and lowest number\n function recursiveHighLow(data) {\n if(data === undefined) {\n return undefined;\n } else if(data instanceof Array) {\n for (var i = 0; i < data.length; i++) {\n recursiveHighLow(data[i]);\n }\n } else {\n var value = dimension ? +data[dimension] : +data;\n\n if (findHigh && value > highLow.high) {\n highLow.high = value;\n }\n\n if (findLow && value < highLow.low) {\n highLow.low = value;\n }\n }\n }\n\n // Start to find highest and lowest number recursively\n if(findHigh || findLow) {\n recursiveHighLow(data);\n }\n\n // Overrides of high / low based on reference value, it will make sure that the invisible reference value is\n // used to generate the chart. This is useful when the chart always needs to contain the position of the\n // invisible reference value in the view i.e. for bipolar scales.\n if (options.referenceValue || options.referenceValue === 0) {\n highLow.high = Math.max(options.referenceValue, highLow.high);\n highLow.low = Math.min(options.referenceValue, highLow.low);\n }\n\n // If high and low are the same because of misconfiguration or flat data (only the same value) we need\n // to set the high or low to 0 depending on the polarity\n if (highLow.high <= highLow.low) {\n // If both values are 0 we set high to 1\n if (highLow.low === 0) {\n highLow.high = 1;\n } else if (highLow.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n highLow.high = 0;\n } else if (highLow.high > 0) {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n } else {\n // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors\n highLow.high = 1;\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if a value can be safely coerced to a number. This includes all values except null which result in finite numbers when coerced. This excludes NaN, since it's not finite.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNumeric = function(value) {\n return value === null ? false : isFinite(value);\n };\n\n /**\n * Returns true on all falsey values except the numeric value 0.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {boolean}\n */\n Chartist.isFalseyButZero = function(value) {\n return !value && value !== 0;\n };\n\n /**\n * Returns a number if the passed parameter is a valid number or the function will return undefined. On all other values than a valid number, this function will return undefined.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {*}\n */\n Chartist.getNumberOrUndefined = function(value) {\n return Chartist.isNumeric(value) ? +value : undefined;\n };\n\n /**\n * Checks if provided value object is multi value (contains x or y properties)\n *\n * @memberof Chartist.Core\n * @param value\n */\n Chartist.isMultiValue = function(value) {\n return typeof value === 'object' && ('x' in value || 'y' in value);\n };\n\n /**\n * Gets a value from a dimension `value.x` or `value.y` while returning value directly if it's a valid numeric value. If the value is not numeric and it's falsey this function will return `defaultValue`.\n *\n * @memberof Chartist.Core\n * @param value\n * @param dimension\n * @param defaultValue\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isMultiValue(value)) {\n return Chartist.getNumberOrUndefined(value[dimension || 'y']);\n } else {\n return Chartist.getNumberOrUndefined(value);\n }\n };\n\n /**\n * Pollard Rho Algorithm to find smallest factor of an integer value. There are more efficient algorithms for factorization, but this one is quite efficient and not so complex.\n *\n * @memberof Chartist.Core\n * @param {Number} num An integer number where the smallest factor should be searched for\n * @returns {Number} The smallest integer factor of the parameter num.\n */\n Chartist.rho = function(num) {\n if(num === 1) {\n return num;\n }\n\n function gcd(p, q) {\n if (p % q === 0) {\n return q;\n } else {\n return gcd(q, p % q);\n }\n }\n\n function f(x) {\n return x * x + 1;\n }\n\n var x1 = 2, x2 = 2, divisor;\n if (num % 2 === 0) {\n return 2;\n }\n\n do {\n x1 = f(x1) % num;\n x2 = f(f(x2)) % num;\n divisor = gcd(Math.abs(x1 - x2), num);\n } while (divisor === 1);\n\n return divisor;\n };\n\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Number} axisLength The length of the Axis used for\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Number} scaleMinSpace The minimum projected length a step should result in\n * @param {Boolean} onlyInteger\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, onlyInteger) {\n var i,\n optimizationCounter = 0,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.step = Math.pow(10, bounds.oom);\n bounds.min = Math.floor(bounds.low / bounds.step) * bounds.step;\n bounds.max = Math.ceil(bounds.high / bounds.step) * bounds.step;\n bounds.range = bounds.max - bounds.min;\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n // If we are already below the scaleMinSpace value we will scale up\n var length = Chartist.projectLength(axisLength, bounds.step, bounds);\n var scaleUp = length < scaleMinSpace;\n var smallestFactor = onlyInteger ? Chartist.rho(bounds.range) : 0;\n\n // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1\n if(onlyInteger && Chartist.projectLength(axisLength, 1, bounds) >= scaleMinSpace) {\n bounds.step = 1;\n } else if(onlyInteger && smallestFactor < bounds.step && Chartist.projectLength(axisLength, smallestFactor, bounds) >= scaleMinSpace) {\n // If step 1 was too small, we can try the smallest factor of range\n // If the smallest factor is smaller than the current bounds.step and the projected length of smallest factor\n // is larger than the scaleMinSpace we should go for it.\n bounds.step = smallestFactor;\n } else {\n // Trying to divide or multiply by 2 and find the best step value\n while (true) {\n if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) {\n bounds.step /= 2;\n if(onlyInteger && bounds.step % 1 !== 0) {\n bounds.step *= 2;\n break;\n }\n } else {\n break;\n }\n\n if(optimizationCounter++ > 1000) {\n throw new Error('Exceeded maximum number of iterations while optimizing scale step!');\n }\n }\n }\n\n var EPSILON = 2.221E-16;\n bounds.step = Math.max(bounds.step, EPSILON);\n function safeIncrement(value, increment) {\n // If increment is too small use *= (1+EPSILON) as a simple nextafter\n if (value === (value += increment)) {\n \tvalue *= (1 + (increment > 0 ? EPSILON : -EPSILON));\n }\n return value;\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while (newMin + bounds.step <= bounds.low) {\n \tnewMin = safeIncrement(newMin, bounds.step);\n }\n while (newMax - bounds.step >= bounds.high) {\n \tnewMax = safeIncrement(newMax, -bounds.step);\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n var values = [];\n for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) {\n var value = Chartist.roundWithPrecision(i);\n if (value !== values[values.length - 1]) {\n values.push(value);\n }\n }\n bounds.values = values;\n return bounds;\n };\n\n /**\n * Calculate cartesian coordinates of polar coordinates\n *\n * @memberof Chartist.Core\n * @param {Number} centerX X-axis coordinates of center point of circle segment\n * @param {Number} centerY X-axis coordinates of center point of circle segment\n * @param {Number} radius Radius of circle segment\n * @param {Number} angleInDegrees Angle of circle segment in degrees\n * @return {{x:Number, y:Number}} Coordinates of point on circumference\n */\n Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) {\n var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;\n\n return {\n x: centerX + (radius * Math.cos(angleInRadians)),\n y: centerY + (radius * Math.sin(angleInRadians))\n };\n };\n\n /**\n * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} [fallbackPadding] The fallback padding if partial padding objects are used\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, fallbackPadding) {\n var hasAxis = !!(options.axisX || options.axisY);\n var yAxisOffset = hasAxis ? options.axisY.offset : 0;\n var xAxisOffset = hasAxis ? options.axisX.offset : 0;\n // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0\n var width = svg.width() || Chartist.quantity(options.width).value || 0;\n var height = svg.height() || Chartist.quantity(options.height).value || 0;\n var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding);\n\n // If settings were to small to cope with offset (legacy) and padding, we'll adjust\n width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom);\n\n var chartRect = {\n padding: normalizedPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n\n if(hasAxis) {\n if (options.axisX.position === 'start') {\n chartRect.y2 = normalizedPadding.top + xAxisOffset;\n chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1);\n } else {\n chartRect.y2 = normalizedPadding.top;\n chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1);\n }\n\n if (options.axisY.position === 'start') {\n chartRect.x1 = normalizedPadding.left + yAxisOffset;\n chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1);\n } else {\n chartRect.x1 = normalizedPadding.left;\n chartRect.x2 = Math.max(width - normalizedPadding.right - yAxisOffset, chartRect.x1 + 1);\n }\n } else {\n chartRect.x1 = normalizedPadding.left;\n chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1);\n chartRect.y2 = normalizedPadding.top;\n chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1);\n }\n\n return chartRect;\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param position\n * @param index\n * @param axis\n * @param offset\n * @param length\n * @param group\n * @param classes\n * @param eventEmitter\n */\n Chartist.createGrid = function(position, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = position;\n positionalData[axis.units.pos + '2'] = position;\n positionalData[axis.counterUnits.pos + '1'] = offset;\n positionalData[axis.counterUnits.pos + '2'] = offset + length;\n\n var gridElement = group.elem('line', positionalData, classes.join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw',\n Chartist.extend({\n type: 'grid',\n axis: axis,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a grid background rect and emits the draw event.\n *\n * @memberof Chartist.Core\n * @param gridGroup\n * @param chartRect\n * @param className\n * @param eventEmitter\n */\n Chartist.createGridBackground = function (gridGroup, chartRect, className, eventEmitter) {\n var gridBackground = gridGroup.elem('rect', {\n x: chartRect.x1,\n y: chartRect.y2,\n width: chartRect.width(),\n height: chartRect.height(),\n }, className, true);\n\n // Event for grid background draw\n eventEmitter.emit('draw', {\n type: 'gridBackground',\n group: gridGroup,\n element: gridBackground\n });\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param position\n * @param length\n * @param index\n * @param labels\n * @param axis\n * @param axisOffset\n * @param labelOffset\n * @param group\n * @param classes\n * @param useForeignObject\n * @param eventEmitter\n */\n Chartist.createLabel = function(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement;\n var positionalData = {};\n\n positionalData[axis.units.pos] = position + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = length;\n positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10);\n\n if(useForeignObject) {\n // We need to set width and height explicitly to px as span will not expand with width and height being\n // 100% in all browsers\n var content = '' +\n labels[index] + ' ';\n\n labelElement = group.foreignObject(content, Chartist.extend({\n style: 'overflow: visible;'\n }, positionalData));\n } else {\n labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]);\n }\n\n eventEmitter.emit('draw', Chartist.extend({\n type: 'label',\n axis: axis,\n index: index,\n group: group,\n element: labelElement,\n text: labels[index]\n }, positionalData));\n };\n\n /**\n * Helper to read series specific options from options object. It automatically falls back to the global option if\n * there is no option in the series options.\n *\n * @param {Object} series Series object\n * @param {Object} options Chartist options object\n * @param {string} key The options key that should be used to obtain the options\n * @returns {*}\n */\n Chartist.getSeriesOption = function(series, options, key) {\n if(series.name && options.series && options.series[series.name]) {\n var seriesOptions = options.series[series.name];\n return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key];\n } else {\n return options[key];\n }\n };\n\n /**\n * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches\n *\n * @memberof Chartist.Core\n * @param {Object} options Options set by user\n * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart\n * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events\n * @return {Object} The consolidated options object from the defaults, base and matching responsive options\n */\n Chartist.optionsProvider = function (options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend({}, options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions(mediaEvent) {\n var previousOptions = currentOptions;\n currentOptions = Chartist.extend({}, baseOptions);\n\n if (responsiveOptions) {\n for (i = 0; i < responsiveOptions.length; i++) {\n var mql = window.matchMedia(responsiveOptions[i][0]);\n if (mql.matches) {\n currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]);\n }\n }\n }\n\n if(eventEmitter && mediaEvent) {\n eventEmitter.emit('optionsChanged', {\n previousOptions: previousOptions,\n currentOptions: currentOptions\n });\n }\n }\n\n function removeMediaQueryListeners() {\n mediaQueryListeners.forEach(function(mql) {\n mql.removeListener(updateCurrentOptions);\n });\n }\n\n if (!window.matchMedia) {\n throw 'window.matchMedia not found! Make sure you\\'re using a polyfill.';\n } else if (responsiveOptions) {\n\n for (i = 0; i < responsiveOptions.length; i++) {\n var mql = window.matchMedia(responsiveOptions[i][0]);\n mql.addListener(updateCurrentOptions);\n mediaQueryListeners.push(mql);\n }\n }\n // Execute initially without an event argument so we get the correct options\n updateCurrentOptions();\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\n\n\n /**\n * Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates\n * valueData property describing the segment.\n *\n * With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any\n * points with undefined values are discarded.\n *\n * **Options**\n * The following options are used to determine how segments are formed\n * ```javascript\n * var options = {\n * // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment.\n * fillHoles: false,\n * // If increasingX is true, the coordinates in all segments have strictly increasing x-values.\n * increasingX: false\n * };\n * ```\n *\n * @memberof Chartist.Core\n * @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn]\n * @param {Array} values List of associated point values in the form [v1, v2 .. vn]\n * @param {Object} options Options set by user\n * @return {Array} List of segments, each containing a pathCoordinates and valueData property.\n */\n Chartist.splitIntoSegments = function(pathCoordinates, valueData, options) {\n var defaultOptions = {\n increasingX: false,\n fillHoles: false\n };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n var segments = [];\n var hole = true;\n\n for(var i = 0; i < pathCoordinates.length; i += 2) {\n // If this value is a \"hole\" we set the hole flag\n if(Chartist.getMultiValue(valueData[i / 2].value) === undefined) {\n // if(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\n if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) {\n // X is not increasing, so we need to make sure we start a new segment\n hole = true;\n }\n\n\n // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment\n if(hole) {\n segments.push({\n pathCoordinates: [],\n valueData: []\n });\n // As we have a valid value now, we are not in a \"hole\" anymore\n hole = false;\n }\n\n // Add to the segment pathCoordinates and valueData\n segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]);\n segments[segments.length - 1].valueData.push(valueData[i / 2]);\n }\n }\n\n return segments;\n };\n}(window, document, Chartist));\n;/**\n * Chartist path interpolation functions.\n *\n * @module Chartist.Interpolation\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n Chartist.Interpolation = {};\n\n /**\n * This interpolation function does not smooth the path and the result is only containing lines and no curves.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.none({\n * fillHoles: false\n * })\n * });\n *\n *\n * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function(options) {\n var defaultOptions = {\n fillHoles: false\n };\n options = Chartist.extend({}, defaultOptions, options);\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for(var i = 0; i < pathCoordinates.length; i += 2) {\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var currData = valueData[i / 2];\n\n if(Chartist.getMultiValue(currData.value) !== undefined) {\n\n if(hole) {\n path.move(currX, currY, false, currData);\n } else {\n path.line(currX, currY, false, currData);\n }\n\n hole = false;\n } else if(!options.fillHoles) {\n hole = true;\n }\n }\n\n return path;\n };\n };\n\n /**\n * Simple smoothing creates horizontal handles that are positioned with a fraction of the length between two data points. You can use the divisor option to specify the amount of smoothing.\n *\n * Simple smoothing can be used instead of `Chartist.Smoothing.cardinal` if you'd like to get rid of the artifacts it produces sometimes. Simple smoothing produces less flowing lines but is accurate by hitting the points and it also doesn't swing below or above the given data point.\n *\n * All smoothing functions within Chartist are factory functions that accept an options parameter. The simple interpolation function accepts one configuration parameter `divisor`, between 1 and ∞, which controls the smoothing characteristics.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.simple({\n * divisor: 2,\n * fillHoles: false\n * })\n * });\n *\n *\n * @memberof Chartist.Interpolation\n * @param {Object} options The options of the simple interpolation factory function.\n * @return {Function}\n */\n Chartist.Interpolation.simple = function(options) {\n var defaultOptions = {\n divisor: 2,\n fillHoles: false\n };\n options = Chartist.extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var prevX, prevY, prevData;\n\n for(var i = 0; i < pathCoordinates.length; i += 2) {\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var currData = valueData[i / 2];\n\n if(currData.value !== undefined) {\n\n if(prevData === undefined) {\n path.move(currX, currY, false, currData);\n } else {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n }\n\n prevX = currX;\n prevY = currY;\n prevData = currData;\n } else if(!options.fillHoles) {\n prevX = currX = prevData = undefined;\n }\n }\n\n return path;\n };\n };\n\n /**\n * Cardinal / Catmull-Rome spline interpolation is the default smoothing function in Chartist. It produces nice results where the splines will always meet the points. It produces some artifacts though when data values are increased or decreased rapidly. The line may not follow a very accurate path and if the line should be accurate this smoothing function does not produce the best results.\n *\n * Cardinal splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`.\n *\n * All smoothing functions within Chartist are factory functions that accept an options parameter. The cardinal interpolation function accepts one configuration parameter `tension`, between 0 and 1, which controls the smoothing intensity.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.cardinal({\n * tension: 1,\n * fillHoles: false\n * })\n * });\n *\n * @memberof Chartist.Interpolation\n * @param {Object} options The options of the cardinal factory function.\n * @return {Function}\n */\n Chartist.Interpolation.cardinal = function(options) {\n var defaultOptions = {\n tension: 1,\n fillHoles: false\n };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n var t = Math.min(1, Math.max(0, options.tension)),\n c = 1 - t;\n\n return function cardinal(pathCoordinates, valueData) {\n // First we try to split the coordinates into segments\n // This is necessary to treat \"holes\" in line charts\n var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, {\n fillHoles: options.fillHoles\n });\n\n if(!segments.length) {\n // If there were no segments return 'Chartist.Interpolation.none'\n return Chartist.Interpolation.none()([]);\n } else if(segments.length > 1) {\n // If the split resulted in more that one segment we need to interpolate each segment individually and join them\n // afterwards together into a single path.\n var paths = [];\n // For each segment we will recurse the cardinal function\n segments.forEach(function(segment) {\n paths.push(cardinal(segment.pathCoordinates, segment.valueData));\n });\n // Join the segment path data into a single path and return\n return Chartist.Svg.Path.join(paths);\n } else {\n // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first\n // segment\n pathCoordinates = segments[0].pathCoordinates;\n valueData = segments[0].valueData;\n\n // If less than two points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates, valueData);\n }\n\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]),\n z;\n\n for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]},\n {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]},\n {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]},\n {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]};\n p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]};\n }\n }\n\n path.curve(\n (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x),\n (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y),\n (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x),\n (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y),\n p[2].x,\n p[2].y,\n false,\n valueData[(i + 2) / 2]\n );\n }\n\n return path;\n }\n };\n };\n\n /**\n * Monotone Cubic spline interpolation produces a smooth curve which preserves monotonicity. Unlike cardinal splines, the curve will not extend beyond the range of y-values of the original data points.\n *\n * Monotone Cubic splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`.\n *\n * The x-values of subsequent points must be increasing to fit a Monotone Cubic spline. If this condition is not met for a pair of adjacent points, then there will be a break in the curve between those data points.\n *\n * All smoothing functions within Chartist are factory functions that accept an options parameter.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.monotoneCubic({\n * fillHoles: false\n * })\n * });\n *\n * @memberof Chartist.Interpolation\n * @param {Object} options The options of the monotoneCubic factory function.\n * @return {Function}\n */\n Chartist.Interpolation.monotoneCubic = function(options) {\n var defaultOptions = {\n fillHoles: false\n };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function monotoneCubic(pathCoordinates, valueData) {\n // First we try to split the coordinates into segments\n // This is necessary to treat \"holes\" in line charts\n var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, {\n fillHoles: options.fillHoles,\n increasingX: true\n });\n\n if(!segments.length) {\n // If there were no segments return 'Chartist.Interpolation.none'\n return Chartist.Interpolation.none()([]);\n } else if(segments.length > 1) {\n // If the split resulted in more that one segment we need to interpolate each segment individually and join them\n // afterwards together into a single path.\n var paths = [];\n // For each segment we will recurse the monotoneCubic fn function\n segments.forEach(function(segment) {\n paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData));\n });\n // Join the segment path data into a single path and return\n return Chartist.Svg.Path.join(paths);\n } else {\n // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first\n // segment\n pathCoordinates = segments[0].pathCoordinates;\n valueData = segments[0].valueData;\n\n // If less than three points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates, valueData);\n }\n\n var xs = [],\n ys = [],\n i,\n n = pathCoordinates.length / 2,\n ms = [],\n ds = [], dys = [], dxs = [],\n path;\n\n // Populate x and y coordinates into separate arrays, for readability\n\n for(i = 0; i < n; i++) {\n xs[i] = pathCoordinates[i * 2];\n ys[i] = pathCoordinates[i * 2 + 1];\n }\n\n // Calculate deltas and derivative\n\n for(i = 0; i < n - 1; i++) {\n dys[i] = ys[i + 1] - ys[i];\n dxs[i] = xs[i + 1] - xs[i];\n ds[i] = dys[i] / dxs[i];\n }\n\n // Determine desired slope (m) at each point using Fritsch-Carlson method\n // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation\n\n ms[0] = ds[0];\n ms[n - 1] = ds[n - 2];\n\n for(i = 1; i < n - 1; i++) {\n if(ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) {\n ms[i] = 0;\n } else {\n ms[i] = 3 * (dxs[i - 1] + dxs[i]) / (\n (2 * dxs[i] + dxs[i - 1]) / ds[i - 1] +\n (dxs[i] + 2 * dxs[i - 1]) / ds[i]);\n\n if(!isFinite(ms[i])) {\n ms[i] = 0;\n }\n }\n }\n\n // Now build a path from the slopes\n\n path = new Chartist.Svg.Path().move(xs[0], ys[0], false, valueData[0]);\n\n for(i = 0; i < n - 1; i++) {\n path.curve(\n // First control point\n xs[i] + dxs[i] / 3,\n ys[i] + ms[i] * dxs[i] / 3,\n // Second control point\n xs[i + 1] - dxs[i] / 3,\n ys[i + 1] - ms[i + 1] * dxs[i] / 3,\n // End point\n xs[i + 1],\n ys[i + 1],\n\n false,\n valueData[i + 1]\n );\n }\n\n return path;\n }\n };\n };\n\n /**\n * Step interpolation will cause the line chart to move in steps rather than diagonal or smoothed lines. This interpolation will create additional points that will also be drawn when the `showPoint` option is enabled.\n *\n * All smoothing functions within Chartist are factory functions that accept an options parameter. The step interpolation function accepts one configuration parameter `postpone`, that can be `true` or `false`. The default value is `true` and will cause the step to occur where the value actually changes. If a different behaviour is needed where the step is shifted to the left and happens before the actual value, this option can be set to `false`.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.step({\n * postpone: true,\n * fillHoles: false\n * })\n * });\n *\n * @memberof Chartist.Interpolation\n * @param options\n * @returns {Function}\n */\n Chartist.Interpolation.step = function(options) {\n var defaultOptions = {\n postpone: true,\n fillHoles: false\n };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n\n var prevX, prevY, prevData;\n\n for (var i = 0; i < pathCoordinates.length; i += 2) {\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var currData = valueData[i / 2];\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\n if(prevData === undefined) {\n path.move(currX, currY, false, currData);\n } else {\n if(options.postpone) {\n // If postponed we should draw the step line with the value of the previous value\n path.line(currX, prevY, false, prevData);\n } else {\n // If not postponed we should draw the step line with the value of the current value\n path.line(prevX, currY, false, currData);\n }\n // Line to the actual point (this should only be a Y-Axis movement\n path.line(currX, currY, false, currData);\n }\n\n prevX = currX;\n prevY = currY;\n prevData = currData;\n } else if(!options.fillHoles) {\n prevX = prevY = prevData = undefined;\n }\n }\n\n return path;\n };\n };\n\n}(window, document, Chartist));\n;/**\n * A very basic event module that helps to generate and catch events.\n *\n * @module Chartist.Event\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n Chartist.EventEmitter = function () {\n var handlers = [];\n\n /**\n * Add an event handler for a specific event\n *\n * @memberof Chartist.Event\n * @param {String} event The event name\n * @param {Function} handler A event handler function\n */\n function addEventHandler(event, handler) {\n handlers[event] = handlers[event] || [];\n handlers[event].push(handler);\n }\n\n /**\n * Remove an event handler of a specific event name or remove all event handlers for a specific event.\n *\n * @memberof Chartist.Event\n * @param {String} event The event name where a specific or all handlers should be removed\n * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed.\n */\n function removeEventHandler(event, handler) {\n // Only do something if there are event handlers with this name existing\n if(handlers[event]) {\n // If handler is set we will look for a specific handler and only remove this\n if(handler) {\n handlers[event].splice(handlers[event].indexOf(handler), 1);\n if(handlers[event].length === 0) {\n delete handlers[event];\n }\n } else {\n // If no handler is specified we remove all handlers for this event\n delete handlers[event];\n }\n }\n }\n\n /**\n * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter.\n *\n * @memberof Chartist.Event\n * @param {String} event The event name that should be triggered\n * @param {*} data Arbitrary data that will be passed to the event handler callback functions\n */\n function emit(event, data) {\n // Only do something if there are event handlers with this name existing\n if(handlers[event]) {\n handlers[event].forEach(function(handler) {\n handler(data);\n });\n }\n\n // Emit event to star event handlers\n if(handlers['*']) {\n handlers['*'].forEach(function(starHandler) {\n starHandler(event, data);\n });\n }\n }\n\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n}(window, document, Chartist));\n;/**\n * This module provides some basic prototype inheritance utilities.\n *\n * @module Chartist.Class\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n function listToArray(list) {\n var arr = [];\n if (list.length) {\n for (var i = 0; i < list.length; i++) {\n arr.push(list[i]);\n }\n }\n return arr;\n }\n\n /**\n * Method to extend from current prototype.\n *\n * @memberof Chartist.Class\n * @param {Object} properties The object that serves as definition for the prototype that gets created for the new class. This object should always contain a constructor property that is the desired constructor for the newly created class.\n * @param {Object} [superProtoOverride] By default extens will use the current class prototype or Chartist.class. With this parameter you can specify any super prototype that will be used.\n * @return {Function} Constructor function of the new class\n *\n * @example\n * var Fruit = Class.extend({\n * color: undefined,\n * sugar: undefined,\n *\n * constructor: function(color, sugar) {\n * this.color = color;\n * this.sugar = sugar;\n * },\n *\n * eat: function() {\n * this.sugar = 0;\n * return this;\n * }\n * });\n *\n * var Banana = Fruit.extend({\n * length: undefined,\n *\n * constructor: function(length, sugar) {\n * Banana.super.constructor.call(this, 'Yellow', sugar);\n * this.length = length;\n * }\n * });\n *\n * var banana = new Banana(20, 40);\n * console.log('banana instanceof Fruit', banana instanceof Fruit);\n * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana));\n * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype);\n * console.log(banana.sugar);\n * console.log(banana.eat().sugar);\n * console.log(banana.color);\n */\n function extend(properties, superProtoOverride) {\n var superProto = superProtoOverride || this.prototype || Chartist.Class;\n var proto = Object.create(superProto);\n\n Chartist.Class.cloneDefinitions(proto, properties);\n\n var constr = function() {\n var fn = proto.constructor || function () {},\n instance;\n\n // If this is linked to the Chartist namespace the constructor was not called with new\n // To provide a fallback we will instantiate here and return the instance\n instance = this === Chartist ? Object.create(proto) : this;\n fn.apply(instance, Array.prototype.slice.call(arguments, 0));\n\n // If this constructor was not called with new we need to return the instance\n // This will not harm when the constructor has been called with new as the returned value is ignored\n return instance;\n };\n\n constr.prototype = proto;\n constr.super = superProto;\n constr.extend = this.extend;\n\n return constr;\n }\n\n // Variable argument list clones args > 0 into args[0] and retruns modified args[0]\n function cloneDefinitions() {\n var args = listToArray(arguments);\n var target = args[0];\n\n args.splice(1, args.length - 1).forEach(function (source) {\n Object.getOwnPropertyNames(source).forEach(function (propName) {\n // If this property already exist in target we delete it first\n delete target[propName];\n // Define the property with the descriptor from source\n Object.defineProperty(target, propName,\n Object.getOwnPropertyDescriptor(source, propName));\n });\n });\n\n return target;\n }\n\n Chartist.Class = {\n extend: extend,\n cloneDefinitions: cloneDefinitions\n };\n\n}(window, document, Chartist));\n;/**\n * Base for all chart types. The methods in Chartist.Base are inherited to all chart types.\n *\n * @module Chartist.Base\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance.\n // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not\n // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage.\n // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html\n // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj\n // The problem is with the label offsets that can't be converted into percentage and affecting the chart container\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @param {Object} [data] Optional data you'd like to set for the chart before it will update. If not specified the update method will use the data that is already configured with the chart.\n * @param {Object} [options] Optional options you'd like to add to the previous options for the chart before it will update. If not specified the update method will use the options that have been already configured with the chart.\n * @param {Boolean} [override] If set to true, the passed options will be used to extend the options that have been configured already. Otherwise the chart default options will be used as the base\n * @memberof Chartist.Base\n */\n function update(data, options, override) {\n if(data) {\n this.data = data || {};\n this.data.labels = this.data.labels || [];\n this.data.series = this.data.series || [];\n // Event for data transformation that allows to manipulate the data before it gets rendered in the charts\n this.eventEmitter.emit('data', {\n type: 'update',\n data: this.data\n });\n }\n\n if(options) {\n this.options = Chartist.extend({}, override ? this.options : this.defaultOptions, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\n // Otherwise we re-create the optionsProvider at this point\n if(!this.initializeTimeoutId) {\n this.optionsProvider.removeMediaQueryListeners();\n this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n }\n }\n\n // Only re-created the chart if it has been initialized yet\n if(!this.initializeTimeoutId) {\n this.createChart(this.optionsProvider.getCurrentOptions());\n }\n\n // Return a reference to the chart object to chain up calls\n return this;\n }\n\n /**\n * This method can be called on the API object of each chart and will un-register all event listeners that were added to other components. This currently includes a window.resize listener as well as media query listeners if any responsive options have been provided. Use this function if you need to destroy and recreate Chartist charts dynamically.\n *\n * @memberof Chartist.Base\n */\n function detach() {\n // Only detach if initialization already occurred on this chart. If this chart still hasn't initialized (therefore\n // the initializationTimeoutId is still a valid timeout reference, we will clear the timeout\n if(!this.initializeTimeoutId) {\n window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\n } else {\n window.clearTimeout(this.initializeTimeoutId);\n }\n\n return this;\n }\n\n /**\n * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop.\n *\n * @memberof Chartist.Base\n * @param {String} event Name of the event. Check the examples for supported events.\n * @param {Function} handler The handler function that will be called when an event with the given name was emitted. This function will receive a data argument which contains event data. See the example for more details.\n */\n function on(event, handler) {\n this.eventEmitter.addEventHandler(event, handler);\n return this;\n }\n\n /**\n * Use this function to un-register event handlers. If the handler function parameter is omitted all handlers for the given event will be un-registered.\n *\n * @memberof Chartist.Base\n * @param {String} event Name of the event for which a handler should be removed\n * @param {Function} [handler] The handler function that that was previously used to register a new event handler. This handler will be removed from the event handler list. If this parameter is omitted then all event handlers for the given event are removed from the list.\n */\n function off(event, handler) {\n this.eventEmitter.removeEventHandler(event, handler);\n return this;\n }\n\n function initialize() {\n // Add window resize listener that re-creates the chart\n window.addEventListener('resize', this.resizeListener);\n\n // Obtain current options based on matching media queries (if responsive options are given)\n // This will also register a listener that is re-creating the chart based on media changes\n this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n // Register options change listener that will trigger a chart update\n this.eventEmitter.addEventHandler('optionsChanged', function() {\n this.update();\n }.bind(this));\n\n // Before the first chart creation we need to register us with all plugins that are configured\n // Initialize all relevant plugins with our chart object and the plugin options specified in the config\n if(this.options.plugins) {\n this.options.plugins.forEach(function(plugin) {\n if(plugin instanceof Array) {\n plugin[0](this, plugin[1]);\n } else {\n plugin(this);\n }\n }.bind(this));\n }\n\n // Event for data transformation that allows to manipulate the data before it gets rendered in the charts\n this.eventEmitter.emit('data', {\n type: 'initial',\n data: this.data\n });\n\n // Create the first chart\n this.createChart(this.optionsProvider.getCurrentOptions());\n\n // As chart is initialized from the event loop now we can reset our timeout reference\n // This is important if the chart gets initialized on the same element twice\n this.initializeTimeoutId = undefined;\n }\n\n /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param defaultOptions\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, defaultOptions, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data || {};\n this.data.labels = this.data.labels || [];\n this.data.series = this.data.series || [];\n this.defaultOptions = defaultOptions;\n this.options = options;\n this.responsiveOptions = responsiveOptions;\n this.eventEmitter = Chartist.EventEmitter();\n this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility');\n this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute');\n this.resizeListener = function resizeListener(){\n this.update();\n }.bind(this);\n\n if(this.container) {\n // If chartist was already initialized in this container we are detaching all event listeners first\n if(this.container.__chartist__) {\n this.container.__chartist__.detach();\n }\n\n this.container.__chartist__ = this;\n }\n\n // Using event loop for first draw to make it possible to register event listeners in the same call stack where\n // the chart was created.\n this.initializeTimeoutId = setTimeout(initialize.bind(this), 0);\n }\n\n // Creating the chart base class\n Chartist.Base = Chartist.Class.extend({\n constructor: Base,\n optionsProvider: undefined,\n container: undefined,\n svg: undefined,\n eventEmitter: undefined,\n createChart: function() {\n throw new Error('Base chart type can\\'t be instantiated!');\n },\n update: update,\n detach: detach,\n on: on,\n off: off,\n version: Chartist.version,\n supportsForeignObject: false\n });\n\n}(window, document, Chartist));\n;/**\n * Chartist SVG module for simple SVG DOM abstraction\n *\n * @module Chartist.Svg\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n /**\n * Chartist.Svg creates a new SVG object wrapper with a starting element. You can use the wrapper to fluently create sub-elements and modify them.\n *\n * @memberof Chartist.Svg\n * @constructor\n * @param {String|Element} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg\n * @param {Object} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added.\n * @param {String} className This class or class list will be added to the SVG element\n * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child\n * @param {Boolean} insertFirst If this param is set to true in conjunction with a parent element the newly created element will be added as first child element in the parent element\n */\n function Svg(name, attributes, className, parent, insertFirst) {\n // If Svg is getting called with an SVG element we just return the wrapper\n if(name instanceof Element) {\n this._node = name;\n } else {\n this._node = document.createElementNS(Chartist.namespaces.svg, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this.attr({\n 'xmlns:ct': Chartist.namespaces.ct\n });\n }\n }\n\n if(attributes) {\n this.attr(attributes);\n }\n\n if(className) {\n this.addClass(className);\n }\n\n if(parent) {\n if (insertFirst && parent._node.firstChild) {\n parent._node.insertBefore(this._node, parent._node.firstChild);\n } else {\n parent._node.appendChild(this._node);\n }\n }\n }\n\n /**\n * Set attributes on the current SVG element of the wrapper you're currently working on.\n *\n * @memberof Chartist.Svg\n * @param {Object|String} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added. If this parameter is a String then the function is used as a getter and will return the attribute value.\n * @param {String} [ns] If specified, the attribute will be obtained using getAttributeNs. In order to write namepsaced attributes you can use the namespace:attribute notation within the attributes object.\n * @return {Object|String} The current wrapper object will be returned so it can be used for chaining or the attribute value if used as getter function.\n */\n function attr(attributes, ns) {\n if(typeof attributes === 'string') {\n if(ns) {\n return this._node.getAttributeNS(ns, attributes);\n } else {\n return this._node.getAttribute(attributes);\n }\n }\n\n Object.keys(attributes).forEach(function(key) {\n // If the attribute value is undefined we can skip this one\n if(attributes[key] === undefined) {\n return;\n }\n\n if (key.indexOf(':') !== -1) {\n var namespacedAttribute = key.split(':');\n this._node.setAttributeNS(Chartist.namespaces[namespacedAttribute[0]], key, attributes[key]);\n } else {\n this._node.setAttribute(key, attributes[key]);\n }\n }.bind(this));\n\n return this;\n }\n\n /**\n * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily.\n *\n * @memberof Chartist.Svg\n * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper\n * @param {Object} [attributes] An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added.\n * @param {String} [className] This class or class list will be added to the SVG element\n * @param {Boolean} [insertFirst] If this param is set to true in conjunction with a parent element the newly created element will be added as first child element in the parent element\n * @return {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, insertFirst) {\n return new Chartist.Svg(name, attributes, className, this, insertFirst);\n }\n\n /**\n * Returns the parent Chartist.SVG wrapper object\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} Returns a Chartist.Svg wrapper around the parent node of the current node. If the parent node is not existing or it's not an SVG node then this function will return null.\n */\n function parent() {\n return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null;\n }\n\n /**\n * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree.\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element\n */\n function root() {\n var node = this._node;\n while(node.nodeName !== 'svg') {\n node = node.parentNode;\n }\n return new Chartist.Svg(node);\n }\n\n /**\n * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper.\n *\n * @memberof Chartist.Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found\n */\n function querySelector(selector) {\n var foundNode = this._node.querySelector(selector);\n return foundNode ? new Chartist.Svg(foundNode) : null;\n }\n\n /**\n * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper.\n *\n * @memberof Chartist.Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found\n */\n function querySelectorAll(selector) {\n var foundNodes = this._node.querySelectorAll(selector);\n return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null;\n }\n\n /**\n * Returns the underlying SVG node for the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Node}\n */\n function getNode() {\n return this._node;\n }\n\n /**\n * This method creates a foreignObject (see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject) that allows to embed HTML content into a SVG graphic. With the help of foreignObjects you can enable the usage of regular HTML elements inside of SVG where they are subject for SVG positioning and transformation but the Browser will use the HTML rendering capabilities for the containing DOM.\n *\n * @memberof Chartist.Svg\n * @param {Node|String} content The DOM Node, or HTML string that will be converted to a DOM Node, that is then placed into and wrapped by the foreignObject\n * @param {String} [attributes] An object with properties that will be added as attributes to the foreignObject element that is created. Attributes with undefined values will not be added.\n * @param {String} [className] This class or class list will be added to the SVG element\n * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child\n * @return {Chartist.Svg} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, attributes, className, insertFirst) {\n // If content is string then we convert it to DOM\n // TODO: Handle case where content is not a string nor a DOM Node\n if(typeof content === 'string') {\n var container = document.createElement('div');\n container.innerHTML = content;\n content = container.firstChild;\n }\n\n // Adding namespace to content element\n content.setAttribute('xmlns', Chartist.namespaces.xmlns);\n\n // Creating the foreignObject without required extension attribute (as described here\n // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement)\n var fnObj = this.elem('foreignObject', attributes, className, insertFirst);\n\n // Add content to foreignObjectElement\n fnObj._node.appendChild(content);\n\n return fnObj;\n }\n\n /**\n * This method adds a new text element to the current Chartist.Svg wrapper.\n *\n * @memberof Chartist.Svg\n * @param {String} t The text that should be added to the text element that is created\n * @return {Chartist.Svg} The same wrapper object that was used to add the newly created element\n */\n function text(t) {\n this._node.appendChild(document.createTextNode(t));\n return this;\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} The same wrapper object that got emptied\n */\n function empty() {\n while (this._node.firstChild) {\n this._node.removeChild(this._node.firstChild);\n }\n\n return this;\n }\n\n /**\n * This method will cause the current wrapper to remove itself from its parent wrapper. Use this method if you'd like to get rid of an element in a given DOM structure.\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} The parent wrapper object of the element that got removed\n */\n function remove() {\n this._node.parentNode.removeChild(this._node);\n return this.parent();\n }\n\n /**\n * This method will replace the element with a new element that can be created outside of the current DOM.\n *\n * @memberof Chartist.Svg\n * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object\n * @return {Chartist.Svg} The wrapper of the new element\n */\n function replace(newElement) {\n this._node.parentNode.replaceChild(newElement._node, this._node);\n return newElement;\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @return {Chartist.Svg} The wrapper of the appended object\n */\n function append(element, insertFirst) {\n if(insertFirst && this._node.firstChild) {\n this._node.insertBefore(element._node, this._node.firstChild);\n } else {\n this._node.appendChild(element._node);\n }\n\n return this;\n }\n\n /**\n * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further.\n *\n * @memberof Chartist.Svg\n * @return {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes() {\n return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\\s+/) : [];\n }\n\n /**\n * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once.\n *\n * @memberof Chartist.Svg\n * @param {String} names A white space separated list of class names\n * @return {Chartist.Svg} The wrapper of the current element\n */\n function addClass(names) {\n this._node.setAttribute('class',\n this.classes(this._node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\n\n return this;\n }\n\n /**\n * Removes one or a space separated list of classes from the current element.\n *\n * @memberof Chartist.Svg\n * @param {String} names A white space separated list of class names\n * @return {Chartist.Svg} The wrapper of the current element\n */\n function removeClass(names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n this._node.setAttribute('class', this.classes(this._node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n\n return this;\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} The wrapper of the current element\n */\n function removeAllClasses() {\n this._node.setAttribute('class', '');\n\n return this;\n }\n\n /**\n * Get element height using `getBoundingClientRect`\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.getBoundingClientRect().height;\n }\n\n /**\n * Get element width using `getBoundingClientRect`\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.getBoundingClientRect().width;\n }\n\n /**\n * The animate function lets you animate the current element with SMIL animations. You can add animations for multiple attributes at the same time by using an animation definition object. This object should contain SMIL animation attributes. Please refer to http://www.w3.org/TR/SVG/animate.html for a detailed specification about the available animation attributes. Additionally an easing property can be passed in the animation definition object. This can be a string with a name of an easing function in `Chartist.Svg.Easing` or an array with four numbers specifying a cubic Bézier curve.\n * **An animations object could look like this:**\n * ```javascript\n * element.animate({\n * opacity: {\n * dur: 1000,\n * from: 0,\n * to: 1\n * },\n * x1: {\n * dur: '1000ms',\n * from: 100,\n * to: 200,\n * easing: 'easeOutQuart'\n * },\n * y1: {\n * dur: '2s',\n * from: 0,\n * to: 100\n * }\n * });\n * ```\n * **Automatic unit conversion**\n * For the `dur` and the `begin` animate attribute you can also omit a unit by passing a number. The number will automatically be converted to milli seconds.\n * **Guided mode**\n * The default behavior of SMIL animations with offset using the `begin` attribute is that the attribute will keep it's original value until the animation starts. Mostly this behavior is not desired as you'd like to have your element attributes already initialized with the animation `from` value even before the animation starts. Also if you don't specify `fill=\"freeze\"` on an animate element or if you delete the animation after it's done (which is done in guided mode) the attribute will switch back to the initial value. This behavior is also not desired when performing simple one-time animations. For one-time animations you'd want to trigger animations immediately instead of relative to the document begin time. That's why in guided mode Chartist.Svg will also use the `begin` property to schedule a timeout and manually start the animation after the timeout. If you're using multiple SMIL definition objects for an attribute (in an array), guided mode will be disabled for this attribute, even if you explicitly enabled it.\n * If guided mode is enabled the following behavior is added:\n * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation\n * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation)\n * - The animate element will be forced to use `fill=\"freeze\"`\n * - The animation will be triggered with `beginElement()` in a timeout where `begin` of the definition object is interpreted in milli seconds. If no `begin` was specified the timeout is triggered immediately.\n * - After the animation the element attribute value will be set to the `to` value of the animation\n * - The animate element is deleted from the DOM\n *\n * @memberof Chartist.Svg\n * @param {Object} animations An animations object where the property keys are the attributes you'd like to animate. The properties should be objects again that contain the SMIL animation attributes (usually begin, dur, from, and to). The property begin and dur is auto converted (see Automatic unit conversion). You can also schedule multiple animations for the same attribute by passing an Array of SMIL definition objects. Attributes that contain an array of SMIL definition objects will not be executed in guided mode.\n * @param {Boolean} guided Specify if guided mode should be activated for this animation (see Guided mode). If not otherwise specified, guided mode will be activated.\n * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends.\n * @return {Chartist.Svg} The current element where the animation was added\n */\n function animate(animations, guided, eventEmitter) {\n if(guided === undefined) {\n guided = true;\n }\n\n Object.keys(animations).forEach(function createAnimateForAttributes(attribute) {\n\n function createAnimate(animationDefinition, guided) {\n var attributeProperties = {},\n animate,\n timeout,\n easing;\n\n // Check if an easing is specified in the definition object and delete it from the object as it will not\n // be part of the animate element attributes.\n if(animationDefinition.easing) {\n // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object\n easing = animationDefinition.easing instanceof Array ?\n animationDefinition.easing :\n Chartist.Svg.Easing[animationDefinition.easing];\n delete animationDefinition.easing;\n }\n\n // If numeric dur or begin was provided we assume milli seconds\n animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms');\n animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms');\n\n if(easing) {\n animationDefinition.calcMode = 'spline';\n animationDefinition.keySplines = easing.join(' ');\n animationDefinition.keyTimes = '0;1';\n }\n\n // Adding \"fill: freeze\" if we are in guided mode and set initial attribute values\n if(guided) {\n animationDefinition.fill = 'freeze';\n // Animated property on our element should already be set to the animation from value in guided mode\n attributeProperties[attribute] = animationDefinition.from;\n this.attr(attributeProperties);\n\n // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin\n // which needs to be in ms aside\n timeout = Chartist.quantity(animationDefinition.begin || 0).value;\n animationDefinition.begin = 'indefinite';\n }\n\n animate = this.elem('animate', Chartist.extend({\n attributeName: attribute\n }, animationDefinition));\n\n if(guided) {\n // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout\n setTimeout(function() {\n // If beginElement fails we set the animated attribute to the end position and remove the animate element\n // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in\n // the browser. (Currently FF 34 does not support animate elements in foreignObjects)\n try {\n animate._node.beginElement();\n } catch(err) {\n // Set animated attribute to current animated value\n attributeProperties[attribute] = animationDefinition.to;\n this.attr(attributeProperties);\n // Remove the animate element as it's no longer required\n animate.remove();\n }\n }.bind(this), timeout);\n }\n\n if(eventEmitter) {\n animate._node.addEventListener('beginEvent', function handleBeginEvent() {\n eventEmitter.emit('animationBegin', {\n element: this,\n animate: animate._node,\n params: animationDefinition\n });\n }.bind(this));\n }\n\n animate._node.addEventListener('endEvent', function handleEndEvent() {\n if(eventEmitter) {\n eventEmitter.emit('animationEnd', {\n element: this,\n animate: animate._node,\n params: animationDefinition\n });\n }\n\n if(guided) {\n // Set animated attribute to current animated value\n attributeProperties[attribute] = animationDefinition.to;\n this.attr(attributeProperties);\n // Remove the animate element as it's no longer required\n animate.remove();\n }\n }.bind(this));\n }\n\n // If current attribute is an array of definition objects we create an animate for each and disable guided mode\n if(animations[attribute] instanceof Array) {\n animations[attribute].forEach(function(animationDefinition) {\n createAnimate.bind(this)(animationDefinition, false);\n }.bind(this));\n } else {\n createAnimate.bind(this)(animations[attribute], guided);\n }\n\n }.bind(this));\n\n return this;\n }\n\n Chartist.Svg = Chartist.Class.extend({\n constructor: Svg,\n attr: attr,\n elem: elem,\n parent: parent,\n root: root,\n querySelector: querySelector,\n querySelectorAll: querySelectorAll,\n getNode: getNode,\n foreignObject: foreignObject,\n text: text,\n empty: empty,\n remove: remove,\n replace: replace,\n append: append,\n classes: classes,\n addClass: addClass,\n removeClass: removeClass,\n removeAllClasses: removeAllClasses,\n height: height,\n width: width,\n animate: animate\n });\n\n /**\n * This method checks for support of a given SVG feature like Extensibility, SVG-animation or the like. Check http://www.w3.org/TR/SVG11/feature for a detailed list.\n *\n * @memberof Chartist.Svg\n * @param {String} feature The SVG 1.1 feature that should be checked for support.\n * @return {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#' + feature, '1.1');\n };\n\n /**\n * This Object contains some standard easing cubic bezier curves. Then can be used with their name in the `Chartist.Svg.animate`. You can also extend the list and use your own name in the `animate` function. Click the show code button to see the available bezier functions.\n *\n * @memberof Chartist.Svg\n */\n var easingCubicBeziers = {\n easeInSine: [0.47, 0, 0.745, 0.715],\n easeOutSine: [0.39, 0.575, 0.565, 1],\n easeInOutSine: [0.445, 0.05, 0.55, 0.95],\n easeInQuad: [0.55, 0.085, 0.68, 0.53],\n easeOutQuad: [0.25, 0.46, 0.45, 0.94],\n easeInOutQuad: [0.455, 0.03, 0.515, 0.955],\n easeInCubic: [0.55, 0.055, 0.675, 0.19],\n easeOutCubic: [0.215, 0.61, 0.355, 1],\n easeInOutCubic: [0.645, 0.045, 0.355, 1],\n easeInQuart: [0.895, 0.03, 0.685, 0.22],\n easeOutQuart: [0.165, 0.84, 0.44, 1],\n easeInOutQuart: [0.77, 0, 0.175, 1],\n easeInQuint: [0.755, 0.05, 0.855, 0.06],\n easeOutQuint: [0.23, 1, 0.32, 1],\n easeInOutQuint: [0.86, 0, 0.07, 1],\n easeInExpo: [0.95, 0.05, 0.795, 0.035],\n easeOutExpo: [0.19, 1, 0.22, 1],\n easeInOutExpo: [1, 0, 0, 1],\n easeInCirc: [0.6, 0.04, 0.98, 0.335],\n easeOutCirc: [0.075, 0.82, 0.165, 1],\n easeInOutCirc: [0.785, 0.135, 0.15, 0.86],\n easeInBack: [0.6, -0.28, 0.735, 0.045],\n easeOutBack: [0.175, 0.885, 0.32, 1.275],\n easeInOutBack: [0.68, -0.55, 0.265, 1.55]\n };\n\n Chartist.Svg.Easing = easingCubicBeziers;\n\n /**\n * This helper class is to wrap multiple `Chartist.Svg` elements into a list where you can call the `Chartist.Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Chartist.Svg` on multiple elements.\n * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`.\n *\n * @memberof Chartist.Svg\n * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll)\n * @constructor\n */\n function SvgList(nodeList) {\n var list = this;\n\n this.svgElements = [];\n for(var i = 0; i < nodeList.length; i++) {\n this.svgElements.push(new Chartist.Svg(nodeList[i]));\n }\n\n // Add delegation methods for Chartist.Svg\n Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) {\n return ['constructor',\n 'parent',\n 'querySelector',\n 'querySelectorAll',\n 'replace',\n 'append',\n 'classes',\n 'height',\n 'width'].indexOf(prototypeProperty) === -1;\n }).forEach(function(prototypeProperty) {\n list[prototypeProperty] = function() {\n var args = Array.prototype.slice.call(arguments, 0);\n list.svgElements.forEach(function(element) {\n Chartist.Svg.prototype[prototypeProperty].apply(element, args);\n });\n return list;\n };\n });\n }\n\n Chartist.Svg.List = Chartist.Class.extend({\n constructor: SvgList\n });\n}(window, document, Chartist));\n;/**\n * Chartist SVG path module for SVG path description creation and modification.\n *\n * @module Chartist.Svg.Path\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n /**\n * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported.\n *\n * @memberof Chartist.Svg.Path\n * @type {Object}\n */\n var elementDescriptions = {\n m: ['x', 'y'],\n l: ['x', 'y'],\n c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'],\n a: ['rx', 'ry', 'xAr', 'lAf', 'sf', 'x', 'y']\n };\n\n /**\n * Default options for newly created SVG path objects.\n *\n * @memberof Chartist.Svg.Path\n * @type {Object}\n */\n var defaultOptions = {\n // The accuracy in digit count after the decimal point. This will be used to round numbers in the SVG path. If this option is set to false then no rounding will be performed.\n accuracy: 3\n };\n\n function element(command, params, pathElements, pos, relative, data) {\n var pathElement = Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params, data ? { data: data } : {} );\n\n pathElements.splice(pos, 0, pathElement);\n }\n\n function forEachParam(pathElements, cb) {\n pathElements.forEach(function(pathElement, pathElementIndex) {\n elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) {\n cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements);\n });\n });\n }\n\n /**\n * Used to construct a new path object.\n *\n * @memberof Chartist.Svg.Path\n * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end)\n * @param {Object} options Options object that overrides the default objects. See default options for more details.\n * @constructor\n */\n function SvgPath(close, options) {\n this.pathElements = [];\n this.pos = 0;\n this.close = close;\n this.options = Chartist.extend({}, defaultOptions, options);\n }\n\n /**\n * Gets or sets the current position (cursor) inside of the path. You can move around the cursor freely but limited to 0 or the count of existing elements. All modifications with element functions will insert new elements at the position of this cursor.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array.\n * @return {Chartist.Svg.Path|Number} If the position parameter was passed then the return value will be the path object for easy call chaining. If no position parameter was passed then the current position is returned.\n */\n function position(pos) {\n if(pos !== undefined) {\n this.pos = Math.max(0, Math.min(this.pathElements.length, pos));\n return this;\n } else {\n return this.pos;\n }\n }\n\n /**\n * Removes elements from the path starting at the current position.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} count Number of path elements that should be removed from the current position.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function remove(count) {\n this.pathElements.splice(this.pos, count);\n return this;\n }\n\n /**\n * Use this function to add a new move SVG path element.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x The x coordinate for the move element.\n * @param {Number} y The y coordinate for the move element.\n * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter)\n * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative, data) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative, data);\n return this;\n }\n\n /**\n * Use this function to add a new line SVG path element.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x The x coordinate for the line element.\n * @param {Number} y The y coordinate for the line element.\n * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter)\n * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative, data) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative, data);\n return this;\n }\n\n /**\n * Use this function to add a new curve SVG path element.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x1 The x coordinate for the first control point of the bezier curve.\n * @param {Number} y1 The y coordinate for the first control point of the bezier curve.\n * @param {Number} x2 The x coordinate for the second control point of the bezier curve.\n * @param {Number} y2 The y coordinate for the second control point of the bezier curve.\n * @param {Number} x The x coordinate for the target point of the curve element.\n * @param {Number} y The y coordinate for the target point of the curve element.\n * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter)\n * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative, data) {\n element('C', {\n x1: +x1,\n y1: +y1,\n x2: +x2,\n y2: +y2,\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative, data);\n return this;\n }\n\n /**\n * Use this function to add a new non-bezier curve SVG path element.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} rx The radius to be used for the x-axis of the arc.\n * @param {Number} ry The radius to be used for the y-axis of the arc.\n * @param {Number} xAr Defines the orientation of the arc\n * @param {Number} lAf Large arc flag\n * @param {Number} sf Sweep flag\n * @param {Number} x The x coordinate for the target point of the curve element.\n * @param {Number} y The y coordinate for the target point of the curve element.\n * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter)\n * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function arc(rx, ry, xAr, lAf, sf, x, y, relative, data) {\n element('A', {\n rx: +rx,\n ry: +ry,\n xAr: +xAr,\n lAf: +lAf,\n sf: +sf,\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative, data);\n return this;\n }\n\n /**\n * Parses an SVG path seen in the d attribute of path elements, and inserts the parsed elements into the existing path object at the current cursor position. Any closing path indicators (Z at the end of the path) will be ignored by the parser as this is provided by the close option in the options of the path object.\n *\n * @memberof Chartist.Svg.Path\n * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function parse(path) {\n // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']]\n var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2')\n .replace(/([0-9])([A-Za-z])/g, '$1 $2')\n .split(/[\\s,]+/)\n .reduce(function(result, element) {\n if(element.match(/[A-Za-z]/)) {\n result.push([]);\n }\n\n result[result.length - 1].push(element);\n return result;\n }, []);\n\n // If this is a closed path we remove the Z at the end because this is determined by the close option\n if(chunks[chunks.length - 1][0].toUpperCase() === 'Z') {\n chunks.pop();\n }\n\n // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters\n // For example {command: 'M', x: '10', y: '10'}\n var elements = chunks.map(function(chunk) {\n var command = chunk.shift(),\n description = elementDescriptions[command.toLowerCase()];\n\n return Chartist.extend({\n command: command\n }, description.reduce(function(result, paramName, index) {\n result[paramName] = +chunk[index];\n return result;\n }, {}));\n });\n\n // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position\n var spliceArgs = [this.pos, 0];\n Array.prototype.push.apply(spliceArgs, elements);\n Array.prototype.splice.apply(this.pathElements, spliceArgs);\n // Increase the internal position by the element count\n this.pos += elements.length;\n\n return this;\n }\n\n /**\n * This function renders to current SVG path object into a final SVG string that can be used in the d attribute of SVG path elements. It uses the accuracy option to round big decimals. If the close parameter was set in the constructor of this path object then a path closing Z will be appended to the output string.\n *\n * @memberof Chartist.Svg.Path\n * @return {String}\n */\n function stringify() {\n var accuracyMultiplier = Math.pow(10, this.options.accuracy);\n\n return this.pathElements.reduce(function(path, pathElement) {\n var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) {\n return this.options.accuracy ?\n (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) :\n pathElement[paramName];\n }.bind(this));\n\n return path + pathElement.command + params.join(',');\n }.bind(this), '') + (this.close ? 'Z' : '');\n }\n\n /**\n * Scales all elements in the current SVG path object. There is an individual parameter for each coordinate. Scaling will also be done for control points of curves, affecting the given coordinate.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements.\n * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function scale(x, y) {\n forEachParam(this.pathElements, function(pathElement, paramName) {\n pathElement[paramName] *= paramName[0] === 'x' ? x : y;\n });\n return this;\n }\n\n /**\n * Translates all elements in the current SVG path object. The translation is relative and there is an individual parameter for each coordinate. Translation will also be done for control points of curves, affecting the given coordinate.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements.\n * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function translate(x, y) {\n forEachParam(this.pathElements, function(pathElement, paramName) {\n pathElement[paramName] += paramName[0] === 'x' ? x : y;\n });\n return this;\n }\n\n /**\n * This function will run over all existing path elements and then loop over their attributes. The callback function will be called for every path element attribute that exists in the current path.\n * The method signature of the callback function looks like this:\n * ```javascript\n * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements)\n * ```\n * If something else than undefined is returned by the callback function, this value will be used to replace the old value. This allows you to build custom transformations of path objects that can't be achieved using the basic transformation functions scale and translate.\n *\n * @memberof Chartist.Svg.Path\n * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function transform(transformFnc) {\n forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) {\n var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements);\n if(transformed || transformed === 0) {\n pathElement[paramName] = transformed;\n }\n });\n return this;\n }\n\n /**\n * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned.\n *\n * @memberof Chartist.Svg.Path\n * @param {Boolean} [close] Optional option to set the new cloned path to closed. If not specified or false, the original path close option will be used.\n * @return {Chartist.Svg.Path}\n */\n function clone(close) {\n var c = new Chartist.Svg.Path(close || this.close);\n c.pos = this.pos;\n c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) {\n return Chartist.extend({}, pathElement);\n });\n c.options = Chartist.extend({}, this.options);\n return c;\n }\n\n /**\n * Split a Svg.Path object by a specific command in the path chain. The path chain will be split and an array of newly created paths objects will be returned. This is useful if you'd like to split an SVG path by it's move commands, for example, in order to isolate chunks of drawings.\n *\n * @memberof Chartist.Svg.Path\n * @param {String} command The command you'd like to use to split the path\n * @return {Array}\n */\n function splitByCommand(command) {\n var split = [\n new Chartist.Svg.Path()\n ];\n\n this.pathElements.forEach(function(pathElement) {\n if(pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) {\n split.push(new Chartist.Svg.Path());\n }\n\n split[split.length - 1].pathElements.push(pathElement);\n });\n\n return split;\n }\n\n /**\n * This static function on `Chartist.Svg.Path` is joining multiple paths together into one paths.\n *\n * @memberof Chartist.Svg.Path\n * @param {Array} paths A list of paths to be joined together. The order is important.\n * @param {boolean} close If the newly created path should be a closed path\n * @param {Object} options Path options for the newly created path.\n * @return {Chartist.Svg.Path}\n */\n\n function join(paths, close, options) {\n var joinedPath = new Chartist.Svg.Path(close, options);\n for(var i = 0; i < paths.length; i++) {\n var path = paths[i];\n for(var j = 0; j < path.pathElements.length; j++) {\n joinedPath.pathElements.push(path.pathElements[j]);\n }\n }\n return joinedPath;\n }\n\n Chartist.Svg.Path = Chartist.Class.extend({\n constructor: SvgPath,\n position: position,\n remove: remove,\n move: move,\n line: line,\n curve: curve,\n arc: arc,\n scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone,\n splitByCommand: splitByCommand\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n Chartist.Svg.Path.join = join;\n}(window, document, Chartist));\n;/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n var axisUnits = {\n x: {\n pos: 'x',\n len: 'width',\n dir: 'horizontal',\n rectStart: 'x1',\n rectEnd: 'x2',\n rectOffset: 'y2'\n },\n y: {\n pos: 'y',\n len: 'height',\n dir: 'vertical',\n rectStart: 'y2',\n rectEnd: 'y1',\n rectOffset: 'x1'\n }\n };\n\n function Axis(units, chartRect, ticks, options) {\n this.units = units;\n this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x;\n this.chartRect = chartRect;\n this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart];\n this.gridOffset = chartRect[units.rectOffset];\n this.ticks = ticks;\n this.options = options;\n }\n\n function createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) {\n var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()];\n var projectedValues = this.ticks.map(this.projectValue.bind(this));\n var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n var labelOffset = {\n x: 0,\n y: 0\n };\n\n // TODO: Find better solution for solving this problem\n // Calculate how much space we have available for the label\n var labelLength;\n if(projectedValues[index + 1]) {\n // If we still have one label ahead, we can calculate the distance to the next tick / label\n labelLength = projectedValues[index + 1] - projectedValue;\n } else {\n // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to\n // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will\n // still be visible inside of the chart padding.\n labelLength = Math.max(this.axisLength - projectedValue, 30);\n }\n\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(Chartist.isFalseyButZero(labelValues[index]) && labelValues[index] !== '') {\n return;\n }\n\n // Transform to global coordinates using the chartRect\n // We also need to set the label offset for the createLabel function\n if(this.units.pos === 'x') {\n projectedValue = this.chartRect.x1 + projectedValue;\n labelOffset.x = chartOptions.axisX.labelOffset.x;\n\n // If the labels should be positioned in start position (top side for vertical axis) we need to set a\n // different offset as for positioned with end (bottom)\n if(chartOptions.axisX.position === 'start') {\n labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n }\n } else {\n projectedValue = this.chartRect.y1 - projectedValue;\n labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0);\n\n // If the labels should be positioned in start position (left side for horizontal axis) we need to set a\n // different offset as for positioned with end (right side)\n if(chartOptions.axisY.position === 'start') {\n labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10;\n } else {\n labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10;\n }\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [\n chartOptions.classNames.grid,\n chartOptions.classNames[this.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [\n chartOptions.classNames.label,\n chartOptions.classNames[this.units.dir],\n (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end'])\n ], useForeignObject, eventEmitter);\n }\n }.bind(this));\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\n createGridAndLabels: createGridAndLabels,\n projectValue: function(value, index, data) {\n throw new Error('Base axis can\\'t be instantiated!');\n }\n });\n\n Chartist.Axis.units = axisUnits;\n\n}(window, document, Chartist));\n;/**\n * The auto scale axis uses standard linear scale projection of values along an axis. It uses order of magnitude to find a scale automatically and evaluates the available space in order to find the perfect amount of ticks for your chart.\n * **Options**\n * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.\n * ```javascript\n * var options = {\n * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored\n * high: 100,\n * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored\n * low: 0,\n * // This option will be used when finding the right scale division settings. The amount of ticks on the scale will be determined so that as many ticks as possible will be displayed, while not violating this minimum required space (in pixel).\n * scaleMinSpace: 20,\n * // Can be set to true or false. If set to true, the scale will be generated with whole numbers only.\n * onlyInteger: true,\n * // The reference value can be used to make sure that this value will always be on the chart. This is especially useful on bipolar charts where the bipolar center always needs to be part of the chart.\n * referenceValue: 5\n * };\n * ```\n *\n * @module Chartist.AutoScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function AutoScaleAxis(axisUnit, data, chartRect, options) {\n // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options\n var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos);\n this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger);\n this.range = {\n min: this.bounds.min,\n max: this.bounds.max\n };\n\n Chartist.AutoScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n this.bounds.values,\n options);\n }\n\n function projectValue(value) {\n return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range;\n }\n\n Chartist.AutoScaleAxis = Chartist.Axis.extend({\n constructor: AutoScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * The fixed scale axis uses standard linear projection of values along an axis. It makes use of a divisor option to divide the range provided from the minimum and maximum value or the options high and low that will override the computed minimum and maximum.\n * **Options**\n * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.\n * ```javascript\n * var options = {\n * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored\n * high: 100,\n * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored\n * low: 0,\n * // If specified then the value range determined from minimum to maximum (or low and high) will be divided by this number and ticks will be generated at those division points. The default divisor is 1.\n * divisor: 4,\n * // If ticks is explicitly set, then the axis will not compute the ticks with the divisor, but directly use the data in ticks to determine at what points on the axis a tick need to be generated.\n * ticks: [1, 10, 20, 30]\n * };\n * ```\n *\n * @module Chartist.FixedScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function FixedScaleAxis(axisUnit, data, chartRect, options) {\n var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos);\n this.divisor = options.divisor || 1;\n this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) {\n return highLow.low + (highLow.high - highLow.low) / this.divisor * index;\n }.bind(this));\n this.ticks.sort(function(a, b) {\n return a - b;\n });\n this.range = {\n min: highLow.low,\n max: highLow.high\n };\n\n Chartist.FixedScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n this.ticks,\n options);\n\n this.stepLength = this.axisLength / this.divisor;\n }\n\n function projectValue(value) {\n return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min);\n }\n\n Chartist.FixedScaleAxis = Chartist.Axis.extend({\n constructor: FixedScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * The step axis for step based charts like bar chart or step based line charts. It uses a fixed amount of ticks that will be equally distributed across the whole axis length. The projection is done using the index of the data value rather than the value itself and therefore it's only useful for distribution purpose.\n * **Options**\n * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.\n * ```javascript\n * var options = {\n * // Ticks to be used to distribute across the axis length. As this axis type relies on the index of the value rather than the value, arbitrary data that can be converted to a string can be used as ticks.\n * ticks: ['One', 'Two', 'Three'],\n * // If set to true the full width will be used to distribute the values where the last value will be at the maximum of the axis length. If false the spaces between the ticks will be evenly distributed instead.\n * stretch: true\n * };\n * ```\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, data, chartRect, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options.ticks,\n options);\n\n var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0));\n this.stepLength = this.axisLength / calc;\n }\n\n function projectValue(value, index) {\n return this.stepLength * index;\n }\n\n Chartist.StepAxis = Chartist.Axis.extend({\n constructor: StepAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * The Chartist line chart can be used to draw Line or Scatter charts. If used in the browser you can access the global `Chartist` namespace where you find the `Line` function as a main entry point.\n *\n * For examples on how to use the line chart please check the examples of the `Chartist.Line` method.\n *\n * @module Chartist.Line\n */\n/* global Chartist */\n(function(window, document, Chartist){\n 'use strict';\n\n /**\n * Default options in line charts. Expand the code view to see a detailed list of options with comments.\n *\n * @memberof Chartist.Line\n */\n var defaultOptions = {\n // Options for X-Axis\n axisX: {\n // The offset of the labels to the chart area\n offset: 30,\n // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.\n position: 'end',\n // Allows you to correct label positioning on this axis by positive or negative x and y offset.\n labelOffset: {\n x: 0,\n y: 0\n },\n // If labels should be shown or not\n showLabel: true,\n // If the axis grid should be drawn or not\n showGrid: true,\n // Interpolation function that allows you to intercept the value from the axis label\n labelInterpolationFnc: Chartist.noop,\n // Set the axis type to be used to project values on this axis. If not defined, Chartist.StepAxis will be used for the X-Axis, where the ticks option will be set to the labels in the data and the stretch option will be set to the global fullWidth option. This type can be changed to any axis constructor available (e.g. Chartist.FixedScaleAxis), where all axis options should be present here.\n type: undefined\n },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\n // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.\n position: 'start',\n // Allows you to correct label positioning on this axis by positive or negative x and y offset.\n labelOffset: {\n x: 0,\n y: 0\n },\n // If labels should be shown or not\n showLabel: true,\n // If the axis grid should be drawn or not\n showGrid: true,\n // Interpolation function that allows you to intercept the value from the axis label\n labelInterpolationFnc: Chartist.noop,\n // Set the axis type to be used to project values on this axis. If not defined, Chartist.AutoScaleAxis will be used for the Y-Axis, where the high and low options will be set to the global high and low options. This type can be changed to any axis constructor available (e.g. Chartist.FixedScaleAxis), where all axis options should be present here.\n type: undefined,\n // This value specifies the minimum height in pixel of the scale steps\n scaleMinSpace: 20,\n // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false\n },\n // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')\n width: undefined,\n // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')\n height: undefined,\n // If the line should be drawn or not\n showLine: true,\n // If dots should be drawn or not\n showPoint: true,\n // If the line chart should draw an area\n showArea: false,\n // The base for the area chart that will be used to close the area shape (is normally 0)\n areaBase: 0,\n // Specify if the lines should be smoothed. This value can be true or false where true will result in smoothing using the default smoothing interpolation function Chartist.Interpolation.cardinal and false results in Chartist.Interpolation.none. You can also choose other smoothing / interpolation functions available in the Chartist.Interpolation module, or write your own interpolation function. Check the examples for a brief description.\n lineSmooth: true,\n // If the line chart should add a background fill to the .ct-grids group.\n showGridBackground: false,\n // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value\n low: undefined,\n // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value\n high: undefined,\n // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}\n chartPadding: {\n top: 15,\n right: 15,\n bottom: 5,\n left: 10\n },\n // When set to true, the last grid line on the x-axis is not drawn and the chart elements will expand to the full available width of the chart. For the last label to be drawn correctly you might need to add chart padding or offset the last label with a draw event handler.\n fullWidth: false,\n // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.\n reverseData: false,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n gridBackground: 'ct-grid-background',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal',\n start: 'ct-start',\n end: 'ct-end'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var data = Chartist.normalizeData(this.data, options.reverseData, true);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Create groups for labels, grid and series\n var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n var seriesGroup = this.svg.elem('g');\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n var axisX, axisY;\n\n if(options.axisX.type === undefined) {\n axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.normalized.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNumeric(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNumeric(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY);\n }\n\n axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);\n axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);\n\n if (options.showGridBackground) {\n Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);\n }\n\n // Draw the series\n data.raw.series.forEach(function(series, seriesIndex) {\n var seriesElement = seriesGroup.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesElement.attr({\n 'ct:series-name': series.name,\n 'ct:meta': Chartist.serialize(series.meta)\n });\n\n // Use series class from series data or if not set generate one\n seriesElement.addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [],\n pathData = [];\n\n data.normalized.series[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex])\n };\n pathCoordinates.push(p.x, p.y);\n pathData.push({\n value: value,\n valueIndex: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex)\n });\n }.bind(this));\n\n var seriesOptions = {\n lineSmooth: Chartist.getSeriesOption(series, options, 'lineSmooth'),\n showPoint: Chartist.getSeriesOption(series, options, 'showPoint'),\n showLine: Chartist.getSeriesOption(series, options, 'showLine'),\n showArea: Chartist.getSeriesOption(series, options, 'showArea'),\n areaBase: Chartist.getSeriesOption(series, options, 'areaBase')\n };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.monotoneCubic() : Chartist.Interpolation.none());\n // Interpolating path where pathData will be used to annotate each path element so we can trace back the original\n // index, value and meta data\n var path = smoothing(pathCoordinates, pathData);\n\n // If we should show points we need to create them now to avoid secondary loop\n // Points are drawn from the pathElements returned by the interpolation function\n // Small offset for Firefox to render squares correctly\n if (seriesOptions.showPoint) {\n\n path.pathElements.forEach(function(pathElement) {\n var point = seriesElement.elem('line', {\n x1: pathElement.x,\n y1: pathElement.y,\n x2: pathElement.x + 0.01,\n y2: pathElement.y\n }, options.classNames.point).attr({\n 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNumeric).join(','),\n 'ct:meta': Chartist.serialize(pathElement.data.meta)\n });\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: pathElement.data.value,\n index: pathElement.data.valueIndex,\n meta: pathElement.data.meta,\n series: series,\n seriesIndex: seriesIndex,\n axisX: axisX,\n axisY: axisY,\n group: seriesElement,\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n }.bind(this));\n }\n\n if(seriesOptions.showLine) {\n var line = seriesElement.elem('path', {\n d: path.stringify()\n }, options.classNames.line, true);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: data.normalized.series[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n seriesMeta: series.meta,\n axisX: axisX,\n axisY: axisY,\n group: seriesElement,\n element: line\n });\n }\n\n // Area currently only works with axes that support a range!\n if(seriesOptions.showArea && axisY.range) {\n // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that\n // the area is not drawn outside the chart area.\n var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase);\n\n // In order to form the area we'll first split the path by move commands so we can chunk it up into segments\n path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) {\n // We filter only \"solid\" segments that contain more than one point. Otherwise there's no need for an area\n return pathSegment.pathElements.length > 1;\n }).map(function convertToArea(solidPathSegments) {\n // Receiving the filtered solid path segments we can now convert those segments into fill areas\n var firstElement = solidPathSegments.pathElements[0];\n var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1];\n\n // Cloning the solid path segment with closing option and removing the first move command from the clone\n // We then insert a new move that should start at the area base and draw a straight line up or down\n // at the end of the path we add an additional straight line to the projected area base value\n // As the closing option is set our path will be automatically closed\n return solidPathSegments.clone(true)\n .position(0)\n .remove(1)\n .move(firstElement.x, areaBaseProjected)\n .line(firstElement.x, firstElement.y)\n .position(solidPathSegments.pathElements.length + 1)\n .line(lastElement.x, areaBaseProjected);\n\n }).forEach(function createArea(areaPath) {\n // For each of our newly created area paths, we'll now create path elements by stringifying our path objects\n // and adding the created DOM elements to the correct series group\n var area = seriesElement.elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized.series[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\n axisX: axisX,\n axisY: axisY,\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesElement,\n element: area\n });\n }.bind(this));\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\n axisX: axisX,\n axisY: axisY,\n svg: this.svg,\n options: options\n });\n }\n\n /**\n * This method creates a new line chart.\n *\n * @memberof Chartist.Line\n * @param {String|Node} query A selector query string or directly a DOM element\n * @param {Object} data The data object that needs to consist of a labels and a series array\n * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.\n * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]\n * @return {Object} An object which exposes the API for the created chart\n *\n * @example\n * // Create a simple line chart\n * var data = {\n * // A labels array that can contain any sort of values\n * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],\n * // Our series array that contains series objects or in this case series data arrays\n * series: [\n * [5, 2, 4, 2, 0]\n * ]\n * };\n *\n * // As options we currently only set a static size of 300x200 px\n * var options = {\n * width: '300px',\n * height: '200px'\n * };\n *\n * // In the global name space Chartist we call the Line function to initialize a line chart. As a first parameter we pass in a selector where we would like to get our chart created. Second parameter is the actual data object and as a third parameter we pass in our options\n * new Chartist.Line('.ct-chart', data, options);\n *\n * @example\n * // Use specific interpolation function with configuration from the Chartist.Interpolation module\n *\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [\n * [1, 1, 8, 1, 7]\n * ]\n * }, {\n * lineSmooth: Chartist.Interpolation.cardinal({\n * tension: 0.2\n * })\n * });\n *\n * @example\n * // Create a line chart with responsive options\n *\n * var data = {\n * // A labels array that can contain any sort of values\n * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],\n * // Our series array that contains series objects or in this case series data arrays\n * series: [\n * [5, 2, 4, 2, 0]\n * ]\n * };\n *\n * // In addition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries.\n * var responsiveOptions = [\n * ['screen and (min-width: 641px) and (max-width: 1024px)', {\n * showPoint: false,\n * axisX: {\n * labelInterpolationFnc: function(value) {\n * // Will return Mon, Tue, Wed etc. on medium screens\n * return value.slice(0, 3);\n * }\n * }\n * }],\n * ['screen and (max-width: 640px)', {\n * showLine: false,\n * axisX: {\n * labelInterpolationFnc: function(value) {\n * // Will return M, T, W etc. on small screens\n * return value[0];\n * }\n * }\n * }]\n * ];\n *\n * new Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n function Line(query, data, options, responsiveOptions) {\n Chartist.Line.super.constructor.call(this,\n query,\n data,\n defaultOptions,\n Chartist.extend({}, defaultOptions, options),\n responsiveOptions);\n }\n\n // Creating line chart type in Chartist namespace\n Chartist.Line = Chartist.Base.extend({\n constructor: Line,\n createChart: createChart\n });\n\n}(window, document, Chartist));\n;/**\n * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts.\n *\n * @module Chartist.Bar\n */\n/* global Chartist */\n(function(window, document, Chartist){\n 'use strict';\n\n /**\n * Default options in bar charts. Expand the code view to see a detailed list of options with comments.\n *\n * @memberof Chartist.Bar\n */\n var defaultOptions = {\n // Options for X-Axis\n axisX: {\n // The offset of the chart drawing area to the border of the container\n offset: 30,\n // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.\n position: 'end',\n // Allows you to correct label positioning on this axis by positive or negative x and y offset.\n labelOffset: {\n x: 0,\n y: 0\n },\n // If labels should be shown or not\n showLabel: true,\n // If the axis grid should be drawn or not\n showGrid: true,\n // Interpolation function that allows you to intercept the value from the axis label\n labelInterpolationFnc: Chartist.noop,\n // This value specifies the minimum width in pixel of the scale steps\n scaleMinSpace: 30,\n // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false\n },\n // Options for Y-Axis\n axisY: {\n // The offset of the chart drawing area to the border of the container\n offset: 40,\n // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.\n position: 'start',\n // Allows you to correct label positioning on this axis by positive or negative x and y offset.\n labelOffset: {\n x: 0,\n y: 0\n },\n // If labels should be shown or not\n showLabel: true,\n // If the axis grid should be drawn or not\n showGrid: true,\n // Interpolation function that allows you to intercept the value from the axis label\n labelInterpolationFnc: Chartist.noop,\n // This value specifies the minimum height in pixel of the scale steps\n scaleMinSpace: 20,\n // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false\n },\n // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')\n width: undefined,\n // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')\n height: undefined,\n // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value\n high: undefined,\n // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value\n low: undefined,\n // Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale.\n referenceValue: 0,\n // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}\n chartPadding: {\n top: 15,\n right: 15,\n bottom: 5,\n left: 10\n },\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\n // If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options.\n stackBars: false,\n // If set to 'overlap' this property will force the stacked bars to draw from the zero line.\n // If set to 'accumulate' this property will form a total for each series point. This will also influence the y-axis and the overall bounds of the chart. In stacked mode the seriesBarDistance property will have no effect.\n stackMode: 'accumulate',\n // Inverts the axes of the bar chart in order to draw a horizontal bar chart. Be aware that you also need to invert your axis settings as the Y Axis will now display the labels and the X Axis the values.\n horizontalBars: false,\n // If set to true then each bar will represent a series and the data array is expected to be a one dimensional array of data values rather than a series array of series. This is useful if the bar chart should represent a profile rather than some data over time.\n distributeSeries: false,\n // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.\n reverseData: false,\n // If the bar chart should add a background fill to the .ct-grids group.\n showGridBackground: false,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-bar',\n horizontalBars: 'ct-horizontal-bars',\n label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n gridBackground: 'ct-grid-background',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal',\n start: 'ct-start',\n end: 'ct-end'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var data;\n var highLow;\n\n if(options.distributeSeries) {\n data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');\n data.normalized.series = data.normalized.series.map(function(value) {\n return [value];\n });\n } else {\n data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');\n }\n\n // Create new svg element\n this.svg = Chartist.createSvg(\n this.container,\n options.width,\n options.height,\n options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '')\n );\n\n // Drawing groups in correct order\n var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n var seriesGroup = this.svg.elem('g');\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);\n\n if(options.stackBars && data.normalized.series.length !== 0) {\n\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized.series, function serialSums() {\n return Array.prototype.slice.call(arguments).map(function(value) {\n return value;\n }).reduce(function(prev, curr) {\n return {\n x: prev.x + (curr && curr.x) || 0,\n y: prev.y + (curr && curr.y) || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y');\n\n } else {\n\n highLow = Chartist.getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y');\n }\n\n // Overrides of high / low from settings\n highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high);\n highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n\n var valueAxis,\n labelAxisTicks,\n labelAxis,\n axisX,\n axisY;\n\n // We need to set step count based on some options combinations\n if(options.distributeSeries && options.stackBars) {\n // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should\n // use only the first label for the step axis\n labelAxisTicks = data.normalized.labels.slice(0, 1);\n } else {\n // If distributed series are enabled but stacked bars aren't, we should use the series labels\n // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array\n // as the bars are normalized\n labelAxisTicks = data.normalized.labels;\n }\n\n // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary.\n if(options.horizontalBars) {\n if(options.axisX.type === undefined) {\n valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n }\n\n if(options.axisY.type === undefined) {\n labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\n }));\n }\n }\n\n // Projected 0 point\n var zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0)) : (chartRect.y1 - valueAxis.projectValue(0));\n // Used to track the screen coordinates of stacked bars\n var stackedBarValues = [];\n\n labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);\n valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);\n\n if (options.showGridBackground) {\n Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);\n }\n\n // Draw the series\n data.raw.series.forEach(function(series, seriesIndex) {\n // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc.\n var biPol = seriesIndex - (data.raw.series.length - 1) / 2;\n // Half of the period width between vertical grid lines used to position bars\n var periodHalfLength;\n // Current series SVG element\n var seriesElement;\n\n // We need to set periodHalfLength based on some options combinations\n if(options.distributeSeries && !options.stackBars) {\n // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array\n // which is the series count and divide by 2\n periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2;\n } else if(options.distributeSeries && options.stackBars) {\n // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis\n // length by 2\n periodHalfLength = labelAxis.axisLength / 2;\n } else {\n // On regular bar charts we should just use the series length\n periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2;\n }\n\n // Adding the series group to the series element\n seriesElement = seriesGroup.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesElement.attr({\n 'ct:series-name': series.name,\n 'ct:meta': Chartist.serialize(series.meta)\n });\n\n // Use series class from series data or if not set generate one\n seriesElement.addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n data.normalized.series[seriesIndex].forEach(function(value, valueIndex) {\n var projected,\n bar,\n previousStack,\n labelAxisValueIndex;\n\n // We need to set labelAxisValueIndex based on some options combinations\n if(options.distributeSeries && !options.stackBars) {\n // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection\n // on the step axis for label positioning\n labelAxisValueIndex = seriesIndex;\n } else if(options.distributeSeries && options.stackBars) {\n // If distributed series and stacked bars are enabled, we will only get one bar and therefore always use\n // 0 for projection on the label step axis\n labelAxisValueIndex = 0;\n } else {\n // On regular bar charts we just use the value index to project on the label step axis\n labelAxisValueIndex = valueIndex;\n }\n\n // We need to transform coordinates differently based on the chart layout\n if(options.horizontalBars) {\n projected = {\n x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex])\n }\n }\n\n // If the label axis is a step based axis we will offset the bar into the middle of between two steps using\n // the periodHalfLength value. Also we do arrange the different series so that they align up to each other using\n // the seriesBarDistance. If we don't have a step axis, the bar positions can be chosen freely so we should not\n // add any automated positioning.\n if(labelAxis instanceof Chartist.StepAxis) {\n // Offset to center bar between grid lines, but only if the step axis is not stretched\n if(!labelAxis.options.stretch) {\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n }\n // Using bi-polar offset for multiple series if no stacked bars or series distribution is used\n projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\n }\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[valueIndex] || zeroPoint;\n stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]);\n\n // Skip if value is undefined\n if(value === undefined) {\n return;\n }\n\n var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n\n if(options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) {\n // Stack mode: accumulate (default)\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n // We want backwards compatibility, so the expected fallback without the 'stackMode' option\n // to be the original behaviour (accumulate)\n positions[labelAxis.counterUnits.pos + '1'] = previousStack;\n positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex];\n } else {\n // Draw from the zero line normally\n // This is also the same code for Stack mode: overlap\n positions[labelAxis.counterUnits.pos + '1'] = zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos];\n }\n\n // Limit x and y so that they are within the chart rect\n positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2);\n positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2);\n positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1);\n positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1);\n\n var metaData = Chartist.getMetaData(series, valueIndex);\n\n // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNumeric).join(','),\n 'ct:meta': Chartist.serialize(metaData)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: metaData,\n series: series,\n seriesIndex: seriesIndex,\n axisX: axisX,\n axisY: axisY,\n chartRect: chartRect,\n group: seriesElement,\n element: bar\n }, positions));\n }.bind(this));\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: valueAxis.bounds,\n chartRect: chartRect,\n axisX: axisX,\n axisY: axisY,\n svg: this.svg,\n options: options\n });\n }\n\n /**\n * This method creates a new bar chart and returns API object that you can use for later changes.\n *\n * @memberof Chartist.Bar\n * @param {String|Node} query A selector query string or directly a DOM element\n * @param {Object} data The data object that needs to consist of a labels and a series array\n * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.\n * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]\n * @return {Object} An object which exposes the API for the created chart\n *\n * @example\n * // Create a simple bar chart\n * var data = {\n * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],\n * series: [\n * [5, 2, 4, 2, 0]\n * ]\n * };\n *\n * // In the global name space Chartist we call the Bar function to initialize a bar chart. As a first parameter we pass in a selector where we would like to get our chart created and as a second parameter we pass our data object.\n * new Chartist.Bar('.ct-chart', data);\n *\n * @example\n * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10\n * new Chartist.Bar('.ct-chart', {\n * labels: [1, 2, 3, 4, 5, 6, 7],\n * series: [\n * [1, 3, 2, -5, -3, 1, -6],\n * [-5, -2, -4, -1, 2, -3, 1]\n * ]\n * }, {\n * seriesBarDistance: 12,\n * low: -10,\n * high: 10\n * });\n *\n */\n function Bar(query, data, options, responsiveOptions) {\n Chartist.Bar.super.constructor.call(this,\n query,\n data,\n defaultOptions,\n Chartist.extend({}, defaultOptions, options),\n responsiveOptions);\n }\n\n // Creating bar chart type in Chartist namespace\n Chartist.Bar = Chartist.Base.extend({\n constructor: Bar,\n createChart: createChart\n });\n\n}(window, document, Chartist));\n;/**\n * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts\n *\n * @module Chartist.Pie\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n /**\n * Default options in line charts. Expand the code view to see a detailed list of options with comments.\n *\n * @memberof Chartist.Pie\n */\n var defaultOptions = {\n // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')\n width: undefined,\n // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')\n height: undefined,\n // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}\n chartPadding: 5,\n // Override the class names that are used to generate the SVG structure of the chart\n classNames: {\n chartPie: 'ct-chart-pie',\n chartDonut: 'ct-chart-donut',\n series: 'ct-series',\n slicePie: 'ct-slice-pie',\n sliceDonut: 'ct-slice-donut',\n label: 'ct-label'\n },\n // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise.\n startAngle: 0,\n // An optional total you can specify. By specifying a total value, the sum of the values in the series must be this total in order to draw a full pie. You can use this parameter to draw only parts of a pie or gauge charts.\n total: undefined,\n // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices.\n donut: false,\n // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future.\n // This option can be set as number or string to specify a relative width (i.e. 100 or '30%').\n donutWidth: 60,\n // If a label should be shown or not\n showLabel: true,\n // Label position offset from the standard position which is half distance of the radius. This value can be either positive or negative. Positive values will position the label away from the center.\n labelOffset: 0,\n // This option can be set to 'inside', 'outside' or 'center'. Positioned with 'inside' the labels will be placed on half the distance of the radius to the border of the Pie by respecting the 'labelOffset'. The 'outside' option will place the labels at the border of the pie and 'center' will place the labels in the absolute center point of the chart. The 'center' option only makes sense in conjunction with the 'labelOffset' option.\n labelPosition: 'inside',\n // An interpolation function for the label value\n labelInterpolationFnc: Chartist.noop,\n // Label direction can be 'neutral', 'explode' or 'implode'. The labels anchor will be positioned based on those settings as well as the fact if the labels are on the right or left side of the center of the chart. Usually explode is useful when labels are positioned far away from the center.\n labelDirection: 'neutral',\n // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.\n reverseData: false,\n // If true empty values will be ignored to avoid drawing unncessary slices and labels\n ignoreEmptyValues: false\n };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @return {string}\n */\n function determineAnchorPosition(center, label, direction) {\n var toTheRight = label.x > center.x;\n\n if(toTheRight && direction === 'explode' ||\n !toTheRight && direction === 'implode') {\n return 'start';\n } else if(toTheRight && direction === 'implode' ||\n !toTheRight && direction === 'explode') {\n return 'end';\n } else {\n return 'middle';\n }\n }\n\n /**\n * Creates the pie chart\n *\n * @param options\n */\n function createChart(options) {\n var data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle;\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height,options.donut ? options.classNames.chartDonut : options.classNames.chartPie);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n // Get biggest circle radius possible within chartRect\n radius = Math.min(chartRect.width() / 2, chartRect.height() / 2);\n // Calculate total of all series to get reference value or use total reference from optional options\n totalDataSum = options.total || data.normalized.series.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\n\n var donutWidth = Chartist.quantity(options.donutWidth);\n if (donutWidth.unit === '%') {\n donutWidth.value *= radius / 100;\n }\n\n // If this is a donut chart we need to adjust our radius to enable strokes to be drawn inside\n // Unfortunately this is not possible with the current SVG Spec\n // See this proposal for more details: http://lists.w3.org/Archives/Public/www-svg/2003Oct/0000.html\n radius -= options.donut ? donutWidth.value / 2 : 0;\n\n // If labelPosition is set to `outside` or a donut chart is drawn then the label position is at the radius,\n // if regular pie chart it's half of the radius\n if(options.labelPosition === 'outside' || options.donut) {\n labelRadius = radius;\n } else if(options.labelPosition === 'center') {\n // If labelPosition is center we start with 0 and will later wait for the labelOffset\n labelRadius = 0;\n } else {\n // Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie\n // slice\n labelRadius = radius / 2;\n }\n // Add the offset to the labelRadius where a negative offset means closed to the center of the chart\n labelRadius += options.labelOffset;\n\n // Calculate end angle based on total sum and current data value and offset with padding\n var center = {\n x: chartRect.x1 + chartRect.width() / 2,\n y: chartRect.y2 + chartRect.height() / 2\n };\n\n // Check if there is only one non-zero value in the series array.\n var hasSingleValInSeries = data.raw.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Creating the series groups\n data.raw.series.forEach(function(series, index) {\n seriesGroups[index] = this.svg.elem('g', null, null);\n }.bind(this));\n //if we need to show labels we create the label group now\n if(options.showLabel) {\n labelsGroup = this.svg.elem('g', null, null);\n }\n\n // Draw the series\n // initialize series groups\n data.raw.series.forEach(function(series, index) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return;\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[index].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[index].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(index))\n ].join(' '));\n\n // If the whole dataset is 0 endAngle should be zero. Can't divide by 0.\n var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0);\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2));\n\n // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle\n // with Z and use 359.99 degrees\n if(endAngle - overlappigStartAngle >= 359.99) {\n endAngle = overlappigStartAngle + 359.99;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle);\n\n // Create a new path element for the pie chart. If this isn't a donut chart we should close the path for a correct stroke\n var path = new Chartist.Svg.Path(!options.donut)\n .move(end.x, end.y)\n .arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y);\n\n // If regular pie chart (no donut) we add a line to the center of the circle for completing the pie\n if(!options.donut) {\n path.line(center.x, center.y);\n }\n\n // Create the SVG path\n // If this is a donut chart we add the donut class, otherwise just a regular slice\n var pathElement = seriesGroups[index].elem('path', {\n d: path.stringify()\n }, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie);\n\n // Adding the pie series value to the path\n pathElement.attr({\n 'ct:value': data.normalized.series[index],\n 'ct:meta': Chartist.serialize(series.meta)\n });\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut) {\n pathElement.attr({\n 'style': 'stroke-width: ' + donutWidth.value + 'px'\n });\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: data.normalized.series[index],\n totalDataSum: totalDataSum,\n index: index,\n meta: series.meta,\n series: series,\n group: seriesGroups[index],\n element: pathElement,\n path: path.clone(),\n center: center,\n radius: radius,\n startAngle: startAngle,\n endAngle: endAngle\n });\n\n // If we need to show labels we need to add the label for this slice now\n if(options.showLabel) {\n var labelPosition;\n if(data.raw.series.length === 1) {\n // If we have only 1 series, we can position the label in the center of the pie\n labelPosition = {\n x: center.x,\n y: center.y\n };\n } else {\n // Position at the labelRadius distance from center and between start and end angle\n labelPosition = Chartist.polarToCartesian(\n center.x,\n center.y,\n labelRadius,\n startAngle + (endAngle - startAngle) / 2\n );\n }\n\n var rawValue;\n if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[index])) {\n rawValue = data.normalized.labels[index];\n } else {\n rawValue = data.normalized.series[index];\n }\n\n var interpolatedValue = options.labelInterpolationFnc(rawValue, index);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = labelsGroup.elem('text', {\n dx: labelPosition.x,\n dy: labelPosition.y,\n 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection)\n }, options.classNames.label).text('' + interpolatedValue);\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'label',\n index: index,\n group: labelsGroup,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n }\n\n // Set next startAngle to current endAngle.\n // (except for last slice)\n startAngle = endAngle;\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n chartRect: chartRect,\n svg: this.svg,\n options: options\n });\n }\n\n /**\n * This method creates a new pie chart and returns an object that can be used to redraw the chart.\n *\n * @memberof Chartist.Pie\n * @param {String|Node} query A selector query string or directly a DOM element\n * @param {Object} data The data object in the pie chart needs to have a series property with a one dimensional data array. The values will be normalized against each other and don't necessarily need to be in percentage. The series property can also be an array of value objects that contain a value property and a className property to override the CSS class name for the series group.\n * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.\n * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]\n * @return {Object} An object with a version and an update method to manually redraw the chart\n *\n * @example\n * // Simple pie chart example with four series\n * new Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * new Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * }, {\n * donut: true\n * });\n *\n * @example\n * // Using donut, startAngle and total to draw a gauge chart\n * new Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * donut: true,\n * donutWidth: 20,\n * startAngle: 270,\n * total: 200\n * });\n *\n * @example\n * // Drawing a pie chart with padding and labels that are outside the pie\n * new Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n *\n * @example\n * // Overriding the class names for individual series as well as a name and meta data.\n * // The name will be written as ct:series-name attribute and the meta data will be serialized and written\n * // to a ct:meta attribute.\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * value: 20,\n * name: 'Series 1',\n * className: 'my-custom-class-one',\n * meta: 'Meta One'\n * }, {\n * value: 10,\n * name: 'Series 2',\n * className: 'my-custom-class-two',\n * meta: 'Meta Two'\n * }, {\n * value: 70,\n * name: 'Series 3',\n * className: 'my-custom-class-three',\n * meta: 'Meta Three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n defaultOptions,\n Chartist.extend({}, defaultOptions, options),\n responsiveOptions);\n }\n\n // Creating pie chart type in Chartist namespace\n Chartist.Pie = Chartist.Base.extend({\n constructor: Pie,\n createChart: createChart,\n determineAnchorPosition: determineAnchorPosition\n });\n\n}(window, document, Chartist));\n\nreturn Chartist;\n\n}));\n"]}
\ No newline at end of file
+{"version":3,"sources":["chartist.js"],"names":["root","factory","define","amd","module","exports","this","Chartist","version","window","document","namespaces","svg","xmlns","xhtml","xlink","ct","noop","n","alphaNumerate","String","fromCharCode","extend","target","i","source","sourceProp","arguments","length","prop","Array","replaceAll","str","subStr","newSubStr","replace","RegExp","ensureUnit","value","unit","quantity","input","match","exec","undefined","querySelector","query","Node","times","apply","sum","previous","current","mapMultiply","factor","num","mapAdd","addend","serialMap","arr","cb","result","Math","max","map","e","forEach","index","args","roundWithPrecision","digits","precision","pow","round","escapingMap","&","<",">","\"","'","serialize","data","JSON","stringify","Object","keys","reduce","key","deserialize","parse","createSvg","container","width","height","className","prototype","slice","call","querySelectorAll","filter","getAttributeNS","removeChild","Svg","attr","addClass","_node","style","appendChild","normalizeData","reverse","multi","labelCount","output","raw","normalized","series","getDataArray","every","labels","push","reverseData","safeHasProperty","object","property","hasOwnProperty","isDataHoleValue","isNaN","recursiveConvert","multiValue","getNumberOrUndefined","y","x","normalizePadding","padding","fallback","top","right","bottom","left","getMetaData","meta","orderOfMagnitude","floor","log","abs","LN10","projectLength","axisLength","bounds","range","getAvailableHeight","options","chartPadding","axisX","offset","getHighLow","dimension","recursiveHighLow","findHigh","highLow","high","findLow","low","toUpperCase","Number","MAX_VALUE","referenceValue","min","isNumeric","isFinite","isFalseyButZero","isMultiValue","getMultiValue","rho","gcd","p","q","f","divisor","x1","x2","getBounds","scaleMinSpace","onlyInteger","safeIncrement","increment","EPSILON","newMin","newMax","optimizationCounter","valueRange","oom","step","ceil","numberOfSteps","scaleUp","smallestFactor","Error","values","polarToCartesian","centerX","centerY","radius","angleInDegrees","angleInRadians","PI","cos","sin","createChartRect","fallbackPadding","hasAxis","axisY","yAxisOffset","xAxisOffset","normalizedPadding","chartRect","y1","y2","position","createGrid","axis","group","classes","eventEmitter","positionalData","units","pos","counterUnits","gridElement","elem","join","emit","type","element","createGridBackground","gridGroup","gridBackground","createLabel","axisOffset","labelOffset","useForeignObject","labelElement","len","content","createElement","setAttribute","innerText","foreignObject","text","getSeriesOption","name","seriesOptions","optionsProvider","responsiveOptions","updateCurrentOptions","mediaEvent","previousOptions","currentOptions","baseOptions","mql","matchMedia","matches","removeMediaQueryListeners","mediaQueryListeners","removeListener","addListener","getCurrentOptions","splitIntoSegments","pathCoordinates","valueData","defaultOptions","increasingX","fillHoles","segments","hole","Interpolation","none","path","Path","currX","currY","currData","move","line","simple","d","prevX","prevY","prevData","curve","cardinal","tension","t","c","paths","segment","z","iLen","monotoneCubic","xs","ys","ms","ds","dys","dxs","postpone","EventEmitter","addEventHandler","event","handler","handlers","removeEventHandler","splice","indexOf","starHandler","listToArray","list","properties","superProtoOverride","superProto","Class","proto","create","cloneDefinitions","constr","instance","fn","constructor","getOwnPropertyNames","propName","defineProperty","getOwnPropertyDescriptor","update","override","initializeTimeoutId","createChart","detach","clearTimeout","removeEventListener","resizeListener","on","off","initialize","addEventListener","bind","plugins","plugin","Base","supportsForeignObject","isSupported","supportsAnimations","__chartist__","setTimeout","attributes","parent","insertFirst","Element","createElementNS","xmlns:ct","firstChild","insertBefore","ns","getAttribute","namespacedAttribute","split","setAttributeNS","parentNode","SVGElement","node","nodeName","selector","foundNode","foundNodes","List","getNode","innerHTML","fnObj","createTextNode","empty","remove","newElement","replaceChild","append","trim","names","concat","self","removeClass","removedClasses","removeAllClasses","getBoundingClientRect","animate","animations","guided","attribute","createAnimate","animationDefinition","timeout","easing","attributeProperties","Easing","begin","dur","calcMode","keySplines","keyTimes","fill","from","attributeName","beginElement","err","to","params","SvgList","nodeList","svgElements","prototypeProperty","feature","implementation","hasFeature","easingCubicBeziers","easeInSine","easeOutSine","easeInOutSine","easeInQuad","easeOutQuad","easeInOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","easeInExpo","easeOutExpo","easeInOutExpo","easeInCirc","easeOutCirc","easeInOutCirc","easeInBack","easeOutBack","easeInOutBack","command","pathElements","relative","pathElement","toLowerCase","forEachParam","pathElementIndex","elementDescriptions","paramName","paramIndex","SvgPath","close","count","arc","rx","ry","xAr","lAf","sf","chunks","pop","elements","chunk","shift","description","spliceArgs","accuracyMultiplier","accuracy","scale","translate","transform","transformFnc","transformed","clone","splitByCommand","joinedPath","j","m","l","a","Axis","ticks","axisUnits","rectEnd","rectStart","gridOffset","rectOffset","createGridAndLabels","labelGroup","chartOptions","axisOptions","projectedValues","projectValue","labelValues","labelInterpolationFnc","projectedValue","labelLength","showGrid","classNames","grid","dir","showLabel","label","AutoScaleAxis","axisUnit","FixedScaleAxis","sort","b","stepLength","StepAxis","calc","stretch","chart","seriesGroup","fullWidth","showGridBackground","seriesIndex","seriesElement","ct:series-name","ct:meta","pathData","valueIndex","lineSmooth","showPoint","showLine","showArea","areaBase","smoothing","point","ct:value","seriesMeta","areaBaseProjected","pathSegment","solidPathSegments","firstElement","lastElement","areaPath","area","Line","vertical","horizontal","start","end","distributeSeries","horizontalBars","stackBars","serialSums","prev","curr","valueAxis","labelAxisTicks","labelAxis","zeroPoint","stackedBarValues","periodHalfLength","biPol","projected","bar","previousStack","labelAxisValueIndex","seriesBarDistance","positions","stackMode","metaData","Bar","determineAnchorPosition","center","direction","toTheRight","labelsGroup","labelRadius","totalDataSum","seriesGroups","startAngle","donut","chartDonut","chartPie","total","previousValue","currentValue","donutWidth","donutSolid","labelPosition","hasSingleValInSeries","val","ignoreEmptyValues","endAngle","overlappigStartAngle","innerStart","innerEnd","donutSolidRadius","pathClassName","slicePie","sliceDonut","sliceDonutSolid","strokeWidth","rawValue","interpolatedValue","dx","dy","text-anchor","labelDirection","Pie"],"mappings":"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","file":"chartist.min.js","sourcesContent":["(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define('Chartist', [], function () {\n return (root['Chartist'] = factory());\n });\n } else if (typeof module === 'object' && module.exports) {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like environments that support module.exports,\n // like Node.\n module.exports = factory();\n } else {\n root['Chartist'] = factory();\n }\n}(this, function () {\n\n/* Chartist.js 0.11.0\n * Copyright © 2017 Gion Kunz\n * Free to use under either the WTFPL license or the MIT license.\n * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL\n * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT\n */\n/**\n * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules.\n *\n * @module Chartist.Core\n */\nvar Chartist = {\n version: '0.11.0'\n};\n\n(function (window, document, Chartist) {\n 'use strict';\n\n /**\n * This object contains all namespaces used within Chartist.\n *\n * @memberof Chartist.Core\n * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}}\n */\n Chartist.namespaces = {\n svg: 'http://www.w3.org/2000/svg',\n xmlns: 'http://www.w3.org/2000/xmlns/',\n xhtml: 'http://www.w3.org/1999/xhtml',\n xlink: 'http://www.w3.org/1999/xlink',\n ct: 'http://gionkunz.github.com/chartist-js/ct'\n };\n\n /**\n * Helps to simplify functional style code\n *\n * @memberof Chartist.Core\n * @param {*} n This exact value will be returned by the noop function\n * @return {*} The same value that was provided to the n parameter\n */\n Chartist.noop = function (n) {\n return n;\n };\n\n /**\n * Generates a-z from a number 0 to 26\n *\n * @memberof Chartist.Core\n * @param {Number} n A number from 0 to 26 that will result in a letter a-z\n * @return {String} A character from a-z based on the input number n\n */\n Chartist.alphaNumerate = function (n) {\n // Limit to a-z\n return String.fromCharCode(97 + n % 26);\n };\n\n /**\n * Simple recursive object extend\n *\n * @memberof Chartist.Core\n * @param {Object} target Target object where the source will be merged into\n * @param {Object...} sources This object (objects) will be merged into target and then target is returned\n * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source\n */\n Chartist.extend = function (target) {\n var i, source, sourceProp;\n target = target || {};\n\n for (i = 1; i < arguments.length; i++) {\n source = arguments[i];\n for (var prop in source) {\n sourceProp = source[prop];\n if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) {\n target[prop] = Chartist.extend(target[prop], sourceProp);\n } else {\n target[prop] = sourceProp;\n }\n }\n }\n\n return target;\n };\n\n /**\n * Replaces all occurrences of subStr in str with newSubStr and returns a new string.\n *\n * @memberof Chartist.Core\n * @param {String} str\n * @param {String} subStr\n * @param {String} newSubStr\n * @return {String}\n */\n Chartist.replaceAll = function(str, subStr, newSubStr) {\n return str.replace(new RegExp(subStr, 'g'), newSubStr);\n };\n\n /**\n * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified.\n *\n * @memberof Chartist.Core\n * @param {Number} value\n * @param {String} unit\n * @return {String} Returns the passed number value with unit.\n */\n Chartist.ensureUnit = function(value, unit) {\n if(typeof value === 'number') {\n value = value + unit;\n }\n\n return value;\n };\n\n /**\n * Converts a number or string to a quantity object.\n *\n * @memberof Chartist.Core\n * @param {String|Number} input\n * @return {Object} Returns an object containing the value as number and the unit as string.\n */\n Chartist.quantity = function(input) {\n if (typeof input === 'string') {\n var match = (/^(\\d+)\\s*(.*)$/g).exec(input);\n return {\n value : +match[1],\n unit: match[2] || undefined\n };\n }\n return { value: input };\n };\n\n /**\n * This is a wrapper around document.querySelector that will return the query if it's already of type Node\n *\n * @memberof Chartist.Core\n * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly\n * @return {Node}\n */\n Chartist.querySelector = function(query) {\n return query instanceof Node ? query : document.querySelector(query);\n };\n\n /**\n * Functional style helper to produce array with given length initialized with undefined values\n *\n * @memberof Chartist.Core\n * @param length\n * @return {Array}\n */\n Chartist.times = function(length) {\n return Array.apply(null, new Array(length));\n };\n\n /**\n * Sum helper to be used in reduce functions\n *\n * @memberof Chartist.Core\n * @param previous\n * @param current\n * @return {*}\n */\n Chartist.sum = function(previous, current) {\n return previous + (current ? current : 0);\n };\n\n /**\n * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor.\n *\n * @memberof Chartist.Core\n * @param {Number} factor\n * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array\n */\n Chartist.mapMultiply = function(factor) {\n return function(num) {\n return num * factor;\n };\n };\n\n /**\n * Add helper to be used in `Array.map` for adding a addend to each value of an array.\n *\n * @memberof Chartist.Core\n * @param {Number} addend\n * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array\n */\n Chartist.mapAdd = function(addend) {\n return function(num) {\n return num + addend;\n };\n };\n\n /**\n * Map for multi dimensional arrays where their nested arrays will be mapped in serial. The output array will have the length of the largest nested array. The callback function is called with variable arguments where each argument is the nested array value (or undefined if there are no more values).\n *\n * @memberof Chartist.Core\n * @param arr\n * @param cb\n * @return {Array}\n */\n Chartist.serialMap = function(arr, cb) {\n var result = [],\n length = Math.max.apply(null, arr.map(function(e) {\n return e.length;\n }));\n\n Chartist.times(length).forEach(function(e, index) {\n var args = arr.map(function(e) {\n return e[index];\n });\n\n result[index] = cb.apply(null, args);\n });\n\n return result;\n };\n\n /**\n * This helper function can be used to round values with certain precision level after decimal. This is used to prevent rounding errors near float point precision limit.\n *\n * @memberof Chartist.Core\n * @param {Number} value The value that should be rounded with precision\n * @param {Number} [digits] The number of digits after decimal used to do the rounding\n * @returns {number} Rounded value\n */\n Chartist.roundWithPrecision = function(value, digits) {\n var precision = Math.pow(10, digits || Chartist.precision);\n return Math.round(value * precision) / precision;\n };\n\n /**\n * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number.\n *\n * @memberof Chartist.Core\n * @type {number}\n */\n Chartist.precision = 8;\n\n /**\n * A map with characters to escape for strings to be safely used as attribute values.\n *\n * @memberof Chartist.Core\n * @type {Object}\n */\n Chartist.escapingMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n '\\'': '''\n };\n\n /**\n * This function serializes arbitrary data to a string. In case of data that can't be easily converted to a string, this function will create a wrapper object and serialize the data using JSON.stringify. The outcoming string will always be escaped using Chartist.escapingMap.\n * If called with null or undefined the function will return immediately with null or undefined.\n *\n * @memberof Chartist.Core\n * @param {Number|String|Object} data\n * @return {String}\n */\n Chartist.serialize = function(data) {\n if(data === null || data === undefined) {\n return data;\n } else if(typeof data === 'number') {\n data = ''+data;\n } else if(typeof data === 'object') {\n data = JSON.stringify({data: data});\n }\n\n return Object.keys(Chartist.escapingMap).reduce(function(result, key) {\n return Chartist.replaceAll(result, key, Chartist.escapingMap[key]);\n }, data);\n };\n\n /**\n * This function de-serializes a string previously serialized with Chartist.serialize. The string will always be unescaped using Chartist.escapingMap before it's returned. Based on the input value the return type can be Number, String or Object. JSON.parse is used with try / catch to see if the unescaped string can be parsed into an Object and this Object will be returned on success.\n *\n * @memberof Chartist.Core\n * @param {String} data\n * @return {String|Number|Object}\n */\n Chartist.deserialize = function(data) {\n if(typeof data !== 'string') {\n return data;\n }\n\n data = Object.keys(Chartist.escapingMap).reduce(function(result, key) {\n return Chartist.replaceAll(result, Chartist.escapingMap[key], key);\n }, data);\n\n try {\n data = JSON.parse(data);\n data = data.data !== undefined ? data.data : data;\n } catch(e) {}\n\n return data;\n };\n\n /**\n * Create or reinitialize the SVG element for the chart\n *\n * @memberof Chartist.Core\n * @param {Node} container The containing DOM Node object that will be used to plant the SVG element\n * @param {String} width Set the width of the SVG element. Default is 100%\n * @param {String} height Set the height of the SVG element. Default is 100%\n * @param {String} className Specify a class to be added to the SVG element\n * @return {Object} The created/reinitialized SVG element\n */\n Chartist.createSvg = function (container, width, height, className) {\n var svg;\n\n width = width || '100%';\n height = height || '100%';\n\n // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it\n // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/\n Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) {\n return svg.getAttributeNS(Chartist.namespaces.xmlns, 'ct');\n }).forEach(function removePreviousElement(svg) {\n container.removeChild(svg);\n });\n\n // Create svg object with width and height or use 100% as default\n svg = new Chartist.Svg('svg').attr({\n width: width,\n height: height\n }).addClass(className);\n\n svg._node.style.width = width;\n svg._node.style.height = height;\n\n // Add the DOM node to our container\n container.appendChild(svg._node);\n\n return svg;\n };\n\n /**\n * Ensures that the data object passed as second argument to the charts is present and correctly initialized.\n *\n * @param {Object} data The data object that is passed as second argument to the charts\n * @return {Object} The normalized data object\n */\n Chartist.normalizeData = function(data, reverse, multi) {\n var labelCount;\n var output = {\n raw: data,\n normalized: {}\n };\n\n // Check if we should generate some labels based on existing series data\n output.normalized.series = Chartist.getDataArray({\n series: data.series || []\n }, reverse, multi);\n\n // If all elements of the normalized data array are arrays we're dealing with\n // multi series data and we need to find the largest series if they are un-even\n if (output.normalized.series.every(function(value) {\n return value instanceof Array;\n })) {\n // Getting the series with the the most elements\n labelCount = Math.max.apply(null, output.normalized.series.map(function(series) {\n return series.length;\n }));\n } else {\n // We're dealing with Pie data so we just take the normalized array length\n labelCount = output.normalized.series.length;\n }\n\n output.normalized.labels = (data.labels || []).slice();\n // Padding the labels to labelCount with empty strings\n Array.prototype.push.apply(\n output.normalized.labels,\n Chartist.times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() {\n return '';\n })\n );\n\n if(reverse) {\n Chartist.reverseData(output.normalized);\n }\n\n return output;\n };\n\n /**\n * This function safely checks if an objects has an owned property.\n *\n * @param {Object} object The object where to check for a property\n * @param {string} property The property name\n * @returns {boolean} Returns true if the object owns the specified property\n */\n Chartist.safeHasProperty = function(object, property) {\n return object !== null &&\n typeof object === 'object' &&\n object.hasOwnProperty(property);\n };\n\n /**\n * Checks if a value is considered a hole in the data series.\n *\n * @param {*} value\n * @returns {boolean} True if the value is considered a data hole\n */\n Chartist.isDataHoleValue = function(value) {\n return value === null ||\n value === undefined ||\n (typeof value === 'number' && isNaN(value));\n };\n\n /**\n * Reverses the series, labels and series data arrays.\n *\n * @memberof Chartist.Core\n * @param data\n */\n Chartist.reverseData = function(data) {\n data.labels.reverse();\n data.series.reverse();\n for (var i = 0; i < data.series.length; i++) {\n if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) {\n data.series[i].data.reverse();\n } else if(data.series[i] instanceof Array) {\n data.series[i].reverse();\n }\n }\n };\n\n /**\n * Convert data series into plain array\n *\n * @memberof Chartist.Core\n * @param {Object} data The series object that contains the data to be visualized in the chart\n * @param {Boolean} [reverse] If true the whole data is reversed by the getDataArray call. This will modify the data object passed as first parameter. The labels as well as the series order is reversed. The whole series data arrays are reversed too.\n * @param {Boolean} [multi] Create a multi dimensional array from a series data array where a value object with `x` and `y` values will be created.\n * @return {Array} A plain array that contains the data to be visualized in the chart\n */\n Chartist.getDataArray = function(data, reverse, multi) {\n // Recursively walks through nested arrays and convert string values to numbers and objects with value properties\n // to values. Check the tests in data core -> data normalization for a detailed specification of expected values\n function recursiveConvert(value) {\n if(Chartist.safeHasProperty(value, 'value')) {\n // We are dealing with value object notation so we need to recurse on value property\n return recursiveConvert(value.value);\n } else if(Chartist.safeHasProperty(value, 'data')) {\n // We are dealing with series object notation so we need to recurse on data property\n return recursiveConvert(value.data);\n } else if(value instanceof Array) {\n // Data is of type array so we need to recurse on the series\n return value.map(recursiveConvert);\n } else if(Chartist.isDataHoleValue(value)) {\n // We're dealing with a hole in the data and therefore need to return undefined\n // We're also returning undefined for multi value output\n return undefined;\n } else {\n // We need to prepare multi value output (x and y data)\n if(multi) {\n var multiValue = {};\n\n // Single series value arrays are assumed to specify the Y-Axis value\n // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}]\n // If multi is a string then it's assumed that it specified which dimension should be filled as default\n if(typeof multi === 'string') {\n multiValue[multi] = Chartist.getNumberOrUndefined(value);\n } else {\n multiValue.y = Chartist.getNumberOrUndefined(value);\n }\n\n multiValue.x = value.hasOwnProperty('x') ? Chartist.getNumberOrUndefined(value.x) : multiValue.x;\n multiValue.y = value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : multiValue.y;\n\n return multiValue;\n\n } else {\n // We can return simple data\n return Chartist.getNumberOrUndefined(value);\n }\n }\n }\n\n return data.series.map(recursiveConvert);\n };\n\n /**\n * Converts a number into a padding object.\n *\n * @memberof Chartist.Core\n * @param {Object|Number} padding\n * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed\n * @returns {Object} Returns a padding object containing top, right, bottom, left properties filled with the padding number passed in as argument. If the argument is something else than a number (presumably already a correct padding object) then this argument is directly returned.\n */\n Chartist.normalizePadding = function(padding, fallback) {\n fallback = fallback || 0;\n\n return typeof padding === 'number' ? {\n top: padding,\n right: padding,\n bottom: padding,\n left: padding\n } : {\n top: typeof padding.top === 'number' ? padding.top : fallback,\n right: typeof padding.right === 'number' ? padding.right : fallback,\n bottom: typeof padding.bottom === 'number' ? padding.bottom : fallback,\n left: typeof padding.left === 'number' ? padding.left : fallback\n };\n };\n\n Chartist.getMetaData = function(series, index) {\n var value = series.data ? series.data[index] : series[index];\n return value ? value.meta : undefined;\n };\n\n /**\n * Calculate the order of magnitude for the chart scale\n *\n * @memberof Chartist.Core\n * @param {Number} value The value Range of the chart\n * @return {Number} The order of magnitude\n */\n Chartist.orderOfMagnitude = function (value) {\n return Math.floor(Math.log(Math.abs(value)) / Math.LN10);\n };\n\n /**\n * Project a data length into screen coordinates (pixels)\n *\n * @memberof Chartist.Core\n * @param {Object} axisLength The svg element for the chart\n * @param {Number} length Single data value from a series array\n * @param {Object} bounds All the values to set the bounds of the chart\n * @return {Number} The projected data length in pixels\n */\n Chartist.projectLength = function (axisLength, length, bounds) {\n return length / bounds.range * axisLength;\n };\n\n /**\n * Get the height of the area in the chart for the data series\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @return {Number} The height of the area in the chart for the data series\n */\n Chartist.getAvailableHeight = function (svg, options) {\n return Math.max((Chartist.quantity(options.height).value || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0);\n };\n\n /**\n * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart.\n *\n * @memberof Chartist.Core\n * @param {Array} data The array that contains the data to be visualized in the chart\n * @param {Object} options The Object that contains the chart options\n * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration\n * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.\n */\n Chartist.getHighLow = function (data, options, dimension) {\n // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred\n options = Chartist.extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {});\n\n var highLow = {\n high: options.high === undefined ? -Number.MAX_VALUE : +options.high,\n low: options.low === undefined ? Number.MAX_VALUE : +options.low\n };\n var findHigh = options.high === undefined;\n var findLow = options.low === undefined;\n\n // Function to recursively walk through arrays and find highest and lowest number\n function recursiveHighLow(data) {\n if(data === undefined) {\n return undefined;\n } else if(data instanceof Array) {\n for (var i = 0; i < data.length; i++) {\n recursiveHighLow(data[i]);\n }\n } else {\n var value = dimension ? +data[dimension] : +data;\n\n if (findHigh && value > highLow.high) {\n highLow.high = value;\n }\n\n if (findLow && value < highLow.low) {\n highLow.low = value;\n }\n }\n }\n\n // Start to find highest and lowest number recursively\n if(findHigh || findLow) {\n recursiveHighLow(data);\n }\n\n // Overrides of high / low based on reference value, it will make sure that the invisible reference value is\n // used to generate the chart. This is useful when the chart always needs to contain the position of the\n // invisible reference value in the view i.e. for bipolar scales.\n if (options.referenceValue || options.referenceValue === 0) {\n highLow.high = Math.max(options.referenceValue, highLow.high);\n highLow.low = Math.min(options.referenceValue, highLow.low);\n }\n\n // If high and low are the same because of misconfiguration or flat data (only the same value) we need\n // to set the high or low to 0 depending on the polarity\n if (highLow.high <= highLow.low) {\n // If both values are 0 we set high to 1\n if (highLow.low === 0) {\n highLow.high = 1;\n } else if (highLow.low < 0) {\n // If we have the same negative value for the bounds we set bounds.high to 0\n highLow.high = 0;\n } else if (highLow.high > 0) {\n // If we have the same positive value for the bounds we set bounds.low to 0\n highLow.low = 0;\n } else {\n // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors\n highLow.high = 1;\n highLow.low = 0;\n }\n }\n\n return highLow;\n };\n\n /**\n * Checks if a value can be safely coerced to a number. This includes all values except null which result in finite numbers when coerced. This excludes NaN, since it's not finite.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {Boolean}\n */\n Chartist.isNumeric = function(value) {\n return value === null ? false : isFinite(value);\n };\n\n /**\n * Returns true on all falsey values except the numeric value 0.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {boolean}\n */\n Chartist.isFalseyButZero = function(value) {\n return !value && value !== 0;\n };\n\n /**\n * Returns a number if the passed parameter is a valid number or the function will return undefined. On all other values than a valid number, this function will return undefined.\n *\n * @memberof Chartist.Core\n * @param value\n * @returns {*}\n */\n Chartist.getNumberOrUndefined = function(value) {\n return Chartist.isNumeric(value) ? +value : undefined;\n };\n\n /**\n * Checks if provided value object is multi value (contains x or y properties)\n *\n * @memberof Chartist.Core\n * @param value\n */\n Chartist.isMultiValue = function(value) {\n return typeof value === 'object' && ('x' in value || 'y' in value);\n };\n\n /**\n * Gets a value from a dimension `value.x` or `value.y` while returning value directly if it's a valid numeric value. If the value is not numeric and it's falsey this function will return `defaultValue`.\n *\n * @memberof Chartist.Core\n * @param value\n * @param dimension\n * @param defaultValue\n * @returns {*}\n */\n Chartist.getMultiValue = function(value, dimension) {\n if(Chartist.isMultiValue(value)) {\n return Chartist.getNumberOrUndefined(value[dimension || 'y']);\n } else {\n return Chartist.getNumberOrUndefined(value);\n }\n };\n\n /**\n * Pollard Rho Algorithm to find smallest factor of an integer value. There are more efficient algorithms for factorization, but this one is quite efficient and not so complex.\n *\n * @memberof Chartist.Core\n * @param {Number} num An integer number where the smallest factor should be searched for\n * @returns {Number} The smallest integer factor of the parameter num.\n */\n Chartist.rho = function(num) {\n if(num === 1) {\n return num;\n }\n\n function gcd(p, q) {\n if (p % q === 0) {\n return q;\n } else {\n return gcd(q, p % q);\n }\n }\n\n function f(x) {\n return x * x + 1;\n }\n\n var x1 = 2, x2 = 2, divisor;\n if (num % 2 === 0) {\n return 2;\n }\n\n do {\n x1 = f(x1) % num;\n x2 = f(f(x2)) % num;\n divisor = gcd(Math.abs(x1 - x2), num);\n } while (divisor === 1);\n\n return divisor;\n };\n\n /**\n * Calculate and retrieve all the bounds for the chart and return them in one array\n *\n * @memberof Chartist.Core\n * @param {Number} axisLength The length of the Axis used for\n * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.\n * @param {Number} scaleMinSpace The minimum projected length a step should result in\n * @param {Boolean} onlyInteger\n * @return {Object} All the values to set the bounds of the chart\n */\n Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, onlyInteger) {\n var i,\n optimizationCounter = 0,\n newMin,\n newMax,\n bounds = {\n high: highLow.high,\n low: highLow.low\n };\n\n bounds.valueRange = bounds.high - bounds.low;\n bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);\n bounds.step = Math.pow(10, bounds.oom);\n bounds.min = Math.floor(bounds.low / bounds.step) * bounds.step;\n bounds.max = Math.ceil(bounds.high / bounds.step) * bounds.step;\n bounds.range = bounds.max - bounds.min;\n bounds.numberOfSteps = Math.round(bounds.range / bounds.step);\n\n // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace\n // If we are already below the scaleMinSpace value we will scale up\n var length = Chartist.projectLength(axisLength, bounds.step, bounds);\n var scaleUp = length < scaleMinSpace;\n var smallestFactor = onlyInteger ? Chartist.rho(bounds.range) : 0;\n\n // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1\n if(onlyInteger && Chartist.projectLength(axisLength, 1, bounds) >= scaleMinSpace) {\n bounds.step = 1;\n } else if(onlyInteger && smallestFactor < bounds.step && Chartist.projectLength(axisLength, smallestFactor, bounds) >= scaleMinSpace) {\n // If step 1 was too small, we can try the smallest factor of range\n // If the smallest factor is smaller than the current bounds.step and the projected length of smallest factor\n // is larger than the scaleMinSpace we should go for it.\n bounds.step = smallestFactor;\n } else {\n // Trying to divide or multiply by 2 and find the best step value\n while (true) {\n if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) {\n bounds.step *= 2;\n } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) {\n bounds.step /= 2;\n if(onlyInteger && bounds.step % 1 !== 0) {\n bounds.step *= 2;\n break;\n }\n } else {\n break;\n }\n\n if(optimizationCounter++ > 1000) {\n throw new Error('Exceeded maximum number of iterations while optimizing scale step!');\n }\n }\n }\n\n var EPSILON = 2.221E-16;\n bounds.step = Math.max(bounds.step, EPSILON);\n function safeIncrement(value, increment) {\n // If increment is too small use *= (1+EPSILON) as a simple nextafter\n if (value === (value += increment)) {\n \tvalue *= (1 + (increment > 0 ? EPSILON : -EPSILON));\n }\n return value;\n }\n\n // Narrow min and max based on new step\n newMin = bounds.min;\n newMax = bounds.max;\n while (newMin + bounds.step <= bounds.low) {\n \tnewMin = safeIncrement(newMin, bounds.step);\n }\n while (newMax - bounds.step >= bounds.high) {\n \tnewMax = safeIncrement(newMax, -bounds.step);\n }\n bounds.min = newMin;\n bounds.max = newMax;\n bounds.range = bounds.max - bounds.min;\n\n var values = [];\n for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) {\n var value = Chartist.roundWithPrecision(i);\n if (value !== values[values.length - 1]) {\n values.push(value);\n }\n }\n bounds.values = values;\n return bounds;\n };\n\n /**\n * Calculate cartesian coordinates of polar coordinates\n *\n * @memberof Chartist.Core\n * @param {Number} centerX X-axis coordinates of center point of circle segment\n * @param {Number} centerY X-axis coordinates of center point of circle segment\n * @param {Number} radius Radius of circle segment\n * @param {Number} angleInDegrees Angle of circle segment in degrees\n * @return {{x:Number, y:Number}} Coordinates of point on circumference\n */\n Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) {\n var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;\n\n return {\n x: centerX + (radius * Math.cos(angleInRadians)),\n y: centerY + (radius * Math.sin(angleInRadians))\n };\n };\n\n /**\n * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right\n *\n * @memberof Chartist.Core\n * @param {Object} svg The svg element for the chart\n * @param {Object} options The Object that contains all the optional values for the chart\n * @param {Number} [fallbackPadding] The fallback padding if partial padding objects are used\n * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements\n */\n Chartist.createChartRect = function (svg, options, fallbackPadding) {\n var hasAxis = !!(options.axisX || options.axisY);\n var yAxisOffset = hasAxis ? options.axisY.offset : 0;\n var xAxisOffset = hasAxis ? options.axisX.offset : 0;\n // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0\n var width = svg.width() || Chartist.quantity(options.width).value || 0;\n var height = svg.height() || Chartist.quantity(options.height).value || 0;\n var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding);\n\n // If settings were to small to cope with offset (legacy) and padding, we'll adjust\n width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right);\n height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom);\n\n var chartRect = {\n padding: normalizedPadding,\n width: function () {\n return this.x2 - this.x1;\n },\n height: function () {\n return this.y1 - this.y2;\n }\n };\n\n if(hasAxis) {\n if (options.axisX.position === 'start') {\n chartRect.y2 = normalizedPadding.top + xAxisOffset;\n chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1);\n } else {\n chartRect.y2 = normalizedPadding.top;\n chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1);\n }\n\n if (options.axisY.position === 'start') {\n chartRect.x1 = normalizedPadding.left + yAxisOffset;\n chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1);\n } else {\n chartRect.x1 = normalizedPadding.left;\n chartRect.x2 = Math.max(width - normalizedPadding.right - yAxisOffset, chartRect.x1 + 1);\n }\n } else {\n chartRect.x1 = normalizedPadding.left;\n chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1);\n chartRect.y2 = normalizedPadding.top;\n chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1);\n }\n\n return chartRect;\n };\n\n /**\n * Creates a grid line based on a projected value.\n *\n * @memberof Chartist.Core\n * @param position\n * @param index\n * @param axis\n * @param offset\n * @param length\n * @param group\n * @param classes\n * @param eventEmitter\n */\n Chartist.createGrid = function(position, index, axis, offset, length, group, classes, eventEmitter) {\n var positionalData = {};\n positionalData[axis.units.pos + '1'] = position;\n positionalData[axis.units.pos + '2'] = position;\n positionalData[axis.counterUnits.pos + '1'] = offset;\n positionalData[axis.counterUnits.pos + '2'] = offset + length;\n\n var gridElement = group.elem('line', positionalData, classes.join(' '));\n\n // Event for grid draw\n eventEmitter.emit('draw',\n Chartist.extend({\n type: 'grid',\n axis: axis,\n index: index,\n group: group,\n element: gridElement\n }, positionalData)\n );\n };\n\n /**\n * Creates a grid background rect and emits the draw event.\n *\n * @memberof Chartist.Core\n * @param gridGroup\n * @param chartRect\n * @param className\n * @param eventEmitter\n */\n Chartist.createGridBackground = function (gridGroup, chartRect, className, eventEmitter) {\n var gridBackground = gridGroup.elem('rect', {\n x: chartRect.x1,\n y: chartRect.y2,\n width: chartRect.width(),\n height: chartRect.height(),\n }, className, true);\n\n // Event for grid background draw\n eventEmitter.emit('draw', {\n type: 'gridBackground',\n group: gridGroup,\n element: gridBackground\n });\n };\n\n /**\n * Creates a label based on a projected value and an axis.\n *\n * @memberof Chartist.Core\n * @param position\n * @param length\n * @param index\n * @param labels\n * @param axis\n * @param axisOffset\n * @param labelOffset\n * @param group\n * @param classes\n * @param useForeignObject\n * @param eventEmitter\n */\n Chartist.createLabel = function(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {\n var labelElement;\n var positionalData = {};\n\n positionalData[axis.units.pos] = position + labelOffset[axis.units.pos];\n positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];\n positionalData[axis.units.len] = length;\n positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10);\n\n if(useForeignObject) {\n // We need to set width and height explicitly to px as span will not expand with width and height being\n // 100% in all browsers\n var content = document.createElement('span');\n content.className = classes.join(' ');\n content.setAttribute('xmlns', Chartist.namespaces.xhtml);\n content.innerText = labels[index];\n content.style[axis.units.len] = Math.round(positionalData[axis.units.len]) + 'px';\n content.style[axis.counterUnits.len] = Math.round(positionalData[axis.counterUnits.len]) + 'px';\n\n labelElement = group.foreignObject(content, Chartist.extend({\n style: 'overflow: visible;'\n }, positionalData));\n } else {\n labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]);\n }\n\n eventEmitter.emit('draw', Chartist.extend({\n type: 'label',\n axis: axis,\n index: index,\n group: group,\n element: labelElement,\n text: labels[index]\n }, positionalData));\n };\n\n /**\n * Helper to read series specific options from options object. It automatically falls back to the global option if\n * there is no option in the series options.\n *\n * @param {Object} series Series object\n * @param {Object} options Chartist options object\n * @param {string} key The options key that should be used to obtain the options\n * @returns {*}\n */\n Chartist.getSeriesOption = function(series, options, key) {\n if(series.name && options.series && options.series[series.name]) {\n var seriesOptions = options.series[series.name];\n return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key];\n } else {\n return options[key];\n }\n };\n\n /**\n * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches\n *\n * @memberof Chartist.Core\n * @param {Object} options Options set by user\n * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart\n * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events\n * @return {Object} The consolidated options object from the defaults, base and matching responsive options\n */\n Chartist.optionsProvider = function (options, responsiveOptions, eventEmitter) {\n var baseOptions = Chartist.extend({}, options),\n currentOptions,\n mediaQueryListeners = [],\n i;\n\n function updateCurrentOptions(mediaEvent) {\n var previousOptions = currentOptions;\n currentOptions = Chartist.extend({}, baseOptions);\n\n if (responsiveOptions) {\n for (i = 0; i < responsiveOptions.length; i++) {\n var mql = window.matchMedia(responsiveOptions[i][0]);\n if (mql.matches) {\n currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]);\n }\n }\n }\n\n if(eventEmitter && mediaEvent) {\n eventEmitter.emit('optionsChanged', {\n previousOptions: previousOptions,\n currentOptions: currentOptions\n });\n }\n }\n\n function removeMediaQueryListeners() {\n mediaQueryListeners.forEach(function(mql) {\n mql.removeListener(updateCurrentOptions);\n });\n }\n\n if (!window.matchMedia) {\n throw 'window.matchMedia not found! Make sure you\\'re using a polyfill.';\n } else if (responsiveOptions) {\n\n for (i = 0; i < responsiveOptions.length; i++) {\n var mql = window.matchMedia(responsiveOptions[i][0]);\n mql.addListener(updateCurrentOptions);\n mediaQueryListeners.push(mql);\n }\n }\n // Execute initially without an event argument so we get the correct options\n updateCurrentOptions();\n\n return {\n removeMediaQueryListeners: removeMediaQueryListeners,\n getCurrentOptions: function getCurrentOptions() {\n return Chartist.extend({}, currentOptions);\n }\n };\n };\n\n\n /**\n * Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates\n * valueData property describing the segment.\n *\n * With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any\n * points with undefined values are discarded.\n *\n * **Options**\n * The following options are used to determine how segments are formed\n * ```javascript\n * var options = {\n * // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment.\n * fillHoles: false,\n * // If increasingX is true, the coordinates in all segments have strictly increasing x-values.\n * increasingX: false\n * };\n * ```\n *\n * @memberof Chartist.Core\n * @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn]\n * @param {Array} values List of associated point values in the form [v1, v2 .. vn]\n * @param {Object} options Options set by user\n * @return {Array} List of segments, each containing a pathCoordinates and valueData property.\n */\n Chartist.splitIntoSegments = function(pathCoordinates, valueData, options) {\n var defaultOptions = {\n increasingX: false,\n fillHoles: false\n };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n var segments = [];\n var hole = true;\n\n for(var i = 0; i < pathCoordinates.length; i += 2) {\n // If this value is a \"hole\" we set the hole flag\n if(Chartist.getMultiValue(valueData[i / 2].value) === undefined) {\n // if(valueData[i / 2].value === undefined) {\n if(!options.fillHoles) {\n hole = true;\n }\n } else {\n if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) {\n // X is not increasing, so we need to make sure we start a new segment\n hole = true;\n }\n\n\n // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment\n if(hole) {\n segments.push({\n pathCoordinates: [],\n valueData: []\n });\n // As we have a valid value now, we are not in a \"hole\" anymore\n hole = false;\n }\n\n // Add to the segment pathCoordinates and valueData\n segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]);\n segments[segments.length - 1].valueData.push(valueData[i / 2]);\n }\n }\n\n return segments;\n };\n}(window, document, Chartist));\n;/**\n * Chartist path interpolation functions.\n *\n * @module Chartist.Interpolation\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n Chartist.Interpolation = {};\n\n /**\n * This interpolation function does not smooth the path and the result is only containing lines and no curves.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.none({\n * fillHoles: false\n * })\n * });\n *\n *\n * @memberof Chartist.Interpolation\n * @return {Function}\n */\n Chartist.Interpolation.none = function(options) {\n var defaultOptions = {\n fillHoles: false\n };\n options = Chartist.extend({}, defaultOptions, options);\n return function none(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var hole = true;\n\n for(var i = 0; i < pathCoordinates.length; i += 2) {\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var currData = valueData[i / 2];\n\n if(Chartist.getMultiValue(currData.value) !== undefined) {\n\n if(hole) {\n path.move(currX, currY, false, currData);\n } else {\n path.line(currX, currY, false, currData);\n }\n\n hole = false;\n } else if(!options.fillHoles) {\n hole = true;\n }\n }\n\n return path;\n };\n };\n\n /**\n * Simple smoothing creates horizontal handles that are positioned with a fraction of the length between two data points. You can use the divisor option to specify the amount of smoothing.\n *\n * Simple smoothing can be used instead of `Chartist.Smoothing.cardinal` if you'd like to get rid of the artifacts it produces sometimes. Simple smoothing produces less flowing lines but is accurate by hitting the points and it also doesn't swing below or above the given data point.\n *\n * All smoothing functions within Chartist are factory functions that accept an options parameter. The simple interpolation function accepts one configuration parameter `divisor`, between 1 and ∞, which controls the smoothing characteristics.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.simple({\n * divisor: 2,\n * fillHoles: false\n * })\n * });\n *\n *\n * @memberof Chartist.Interpolation\n * @param {Object} options The options of the simple interpolation factory function.\n * @return {Function}\n */\n Chartist.Interpolation.simple = function(options) {\n var defaultOptions = {\n divisor: 2,\n fillHoles: false\n };\n options = Chartist.extend({}, defaultOptions, options);\n\n var d = 1 / Math.max(1, options.divisor);\n\n return function simple(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n var prevX, prevY, prevData;\n\n for(var i = 0; i < pathCoordinates.length; i += 2) {\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var length = (currX - prevX) * d;\n var currData = valueData[i / 2];\n\n if(currData.value !== undefined) {\n\n if(prevData === undefined) {\n path.move(currX, currY, false, currData);\n } else {\n path.curve(\n prevX + length,\n prevY,\n currX - length,\n currY,\n currX,\n currY,\n false,\n currData\n );\n }\n\n prevX = currX;\n prevY = currY;\n prevData = currData;\n } else if(!options.fillHoles) {\n prevX = currX = prevData = undefined;\n }\n }\n\n return path;\n };\n };\n\n /**\n * Cardinal / Catmull-Rome spline interpolation is the default smoothing function in Chartist. It produces nice results where the splines will always meet the points. It produces some artifacts though when data values are increased or decreased rapidly. The line may not follow a very accurate path and if the line should be accurate this smoothing function does not produce the best results.\n *\n * Cardinal splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`.\n *\n * All smoothing functions within Chartist are factory functions that accept an options parameter. The cardinal interpolation function accepts one configuration parameter `tension`, between 0 and 1, which controls the smoothing intensity.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.cardinal({\n * tension: 1,\n * fillHoles: false\n * })\n * });\n *\n * @memberof Chartist.Interpolation\n * @param {Object} options The options of the cardinal factory function.\n * @return {Function}\n */\n Chartist.Interpolation.cardinal = function(options) {\n var defaultOptions = {\n tension: 1,\n fillHoles: false\n };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n var t = Math.min(1, Math.max(0, options.tension)),\n c = 1 - t;\n\n return function cardinal(pathCoordinates, valueData) {\n // First we try to split the coordinates into segments\n // This is necessary to treat \"holes\" in line charts\n var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, {\n fillHoles: options.fillHoles\n });\n\n if(!segments.length) {\n // If there were no segments return 'Chartist.Interpolation.none'\n return Chartist.Interpolation.none()([]);\n } else if(segments.length > 1) {\n // If the split resulted in more that one segment we need to interpolate each segment individually and join them\n // afterwards together into a single path.\n var paths = [];\n // For each segment we will recurse the cardinal function\n segments.forEach(function(segment) {\n paths.push(cardinal(segment.pathCoordinates, segment.valueData));\n });\n // Join the segment path data into a single path and return\n return Chartist.Svg.Path.join(paths);\n } else {\n // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first\n // segment\n pathCoordinates = segments[0].pathCoordinates;\n valueData = segments[0].valueData;\n\n // If less than two points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates, valueData);\n }\n\n var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]),\n z;\n\n for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) {\n var p = [\n {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]},\n {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]},\n {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]},\n {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]}\n ];\n if (z) {\n if (!i) {\n p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]};\n } else if (iLen - 4 === i) {\n p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]};\n } else if (iLen - 2 === i) {\n p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]};\n p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]};\n }\n } else {\n if (iLen - 4 === i) {\n p[3] = p[2];\n } else if (!i) {\n p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]};\n }\n }\n\n path.curve(\n (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x),\n (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y),\n (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x),\n (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y),\n p[2].x,\n p[2].y,\n false,\n valueData[(i + 2) / 2]\n );\n }\n\n return path;\n }\n };\n };\n\n /**\n * Monotone Cubic spline interpolation produces a smooth curve which preserves monotonicity. Unlike cardinal splines, the curve will not extend beyond the range of y-values of the original data points.\n *\n * Monotone Cubic splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`.\n *\n * The x-values of subsequent points must be increasing to fit a Monotone Cubic spline. If this condition is not met for a pair of adjacent points, then there will be a break in the curve between those data points.\n *\n * All smoothing functions within Chartist are factory functions that accept an options parameter.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.monotoneCubic({\n * fillHoles: false\n * })\n * });\n *\n * @memberof Chartist.Interpolation\n * @param {Object} options The options of the monotoneCubic factory function.\n * @return {Function}\n */\n Chartist.Interpolation.monotoneCubic = function(options) {\n var defaultOptions = {\n fillHoles: false\n };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function monotoneCubic(pathCoordinates, valueData) {\n // First we try to split the coordinates into segments\n // This is necessary to treat \"holes\" in line charts\n var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, {\n fillHoles: options.fillHoles,\n increasingX: true\n });\n\n if(!segments.length) {\n // If there were no segments return 'Chartist.Interpolation.none'\n return Chartist.Interpolation.none()([]);\n } else if(segments.length > 1) {\n // If the split resulted in more that one segment we need to interpolate each segment individually and join them\n // afterwards together into a single path.\n var paths = [];\n // For each segment we will recurse the monotoneCubic fn function\n segments.forEach(function(segment) {\n paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData));\n });\n // Join the segment path data into a single path and return\n return Chartist.Svg.Path.join(paths);\n } else {\n // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first\n // segment\n pathCoordinates = segments[0].pathCoordinates;\n valueData = segments[0].valueData;\n\n // If less than three points we need to fallback to no smoothing\n if(pathCoordinates.length <= 4) {\n return Chartist.Interpolation.none()(pathCoordinates, valueData);\n }\n\n var xs = [],\n ys = [],\n i,\n n = pathCoordinates.length / 2,\n ms = [],\n ds = [], dys = [], dxs = [],\n path;\n\n // Populate x and y coordinates into separate arrays, for readability\n\n for(i = 0; i < n; i++) {\n xs[i] = pathCoordinates[i * 2];\n ys[i] = pathCoordinates[i * 2 + 1];\n }\n\n // Calculate deltas and derivative\n\n for(i = 0; i < n - 1; i++) {\n dys[i] = ys[i + 1] - ys[i];\n dxs[i] = xs[i + 1] - xs[i];\n ds[i] = dys[i] / dxs[i];\n }\n\n // Determine desired slope (m) at each point using Fritsch-Carlson method\n // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation\n\n ms[0] = ds[0];\n ms[n - 1] = ds[n - 2];\n\n for(i = 1; i < n - 1; i++) {\n if(ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) {\n ms[i] = 0;\n } else {\n ms[i] = 3 * (dxs[i - 1] + dxs[i]) / (\n (2 * dxs[i] + dxs[i - 1]) / ds[i - 1] +\n (dxs[i] + 2 * dxs[i - 1]) / ds[i]);\n\n if(!isFinite(ms[i])) {\n ms[i] = 0;\n }\n }\n }\n\n // Now build a path from the slopes\n\n path = new Chartist.Svg.Path().move(xs[0], ys[0], false, valueData[0]);\n\n for(i = 0; i < n - 1; i++) {\n path.curve(\n // First control point\n xs[i] + dxs[i] / 3,\n ys[i] + ms[i] * dxs[i] / 3,\n // Second control point\n xs[i + 1] - dxs[i] / 3,\n ys[i + 1] - ms[i + 1] * dxs[i] / 3,\n // End point\n xs[i + 1],\n ys[i + 1],\n\n false,\n valueData[i + 1]\n );\n }\n\n return path;\n }\n };\n };\n\n /**\n * Step interpolation will cause the line chart to move in steps rather than diagonal or smoothed lines. This interpolation will create additional points that will also be drawn when the `showPoint` option is enabled.\n *\n * All smoothing functions within Chartist are factory functions that accept an options parameter. The step interpolation function accepts one configuration parameter `postpone`, that can be `true` or `false`. The default value is `true` and will cause the step to occur where the value actually changes. If a different behaviour is needed where the step is shifted to the left and happens before the actual value, this option can be set to `false`.\n *\n * @example\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [[1, 2, 8, 1, 7]]\n * }, {\n * lineSmooth: Chartist.Interpolation.step({\n * postpone: true,\n * fillHoles: false\n * })\n * });\n *\n * @memberof Chartist.Interpolation\n * @param options\n * @returns {Function}\n */\n Chartist.Interpolation.step = function(options) {\n var defaultOptions = {\n postpone: true,\n fillHoles: false\n };\n\n options = Chartist.extend({}, defaultOptions, options);\n\n return function step(pathCoordinates, valueData) {\n var path = new Chartist.Svg.Path();\n\n var prevX, prevY, prevData;\n\n for (var i = 0; i < pathCoordinates.length; i += 2) {\n var currX = pathCoordinates[i];\n var currY = pathCoordinates[i + 1];\n var currData = valueData[i / 2];\n\n // If the current point is also not a hole we can draw the step lines\n if(currData.value !== undefined) {\n if(prevData === undefined) {\n path.move(currX, currY, false, currData);\n } else {\n if(options.postpone) {\n // If postponed we should draw the step line with the value of the previous value\n path.line(currX, prevY, false, prevData);\n } else {\n // If not postponed we should draw the step line with the value of the current value\n path.line(prevX, currY, false, currData);\n }\n // Line to the actual point (this should only be a Y-Axis movement\n path.line(currX, currY, false, currData);\n }\n\n prevX = currX;\n prevY = currY;\n prevData = currData;\n } else if(!options.fillHoles) {\n prevX = prevY = prevData = undefined;\n }\n }\n\n return path;\n };\n };\n\n}(window, document, Chartist));\n;/**\n * A very basic event module that helps to generate and catch events.\n *\n * @module Chartist.Event\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n Chartist.EventEmitter = function () {\n var handlers = [];\n\n /**\n * Add an event handler for a specific event\n *\n * @memberof Chartist.Event\n * @param {String} event The event name\n * @param {Function} handler A event handler function\n */\n function addEventHandler(event, handler) {\n handlers[event] = handlers[event] || [];\n handlers[event].push(handler);\n }\n\n /**\n * Remove an event handler of a specific event name or remove all event handlers for a specific event.\n *\n * @memberof Chartist.Event\n * @param {String} event The event name where a specific or all handlers should be removed\n * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed.\n */\n function removeEventHandler(event, handler) {\n // Only do something if there are event handlers with this name existing\n if(handlers[event]) {\n // If handler is set we will look for a specific handler and only remove this\n if(handler) {\n handlers[event].splice(handlers[event].indexOf(handler), 1);\n if(handlers[event].length === 0) {\n delete handlers[event];\n }\n } else {\n // If no handler is specified we remove all handlers for this event\n delete handlers[event];\n }\n }\n }\n\n /**\n * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter.\n *\n * @memberof Chartist.Event\n * @param {String} event The event name that should be triggered\n * @param {*} data Arbitrary data that will be passed to the event handler callback functions\n */\n function emit(event, data) {\n // Only do something if there are event handlers with this name existing\n if(handlers[event]) {\n handlers[event].forEach(function(handler) {\n handler(data);\n });\n }\n\n // Emit event to star event handlers\n if(handlers['*']) {\n handlers['*'].forEach(function(starHandler) {\n starHandler(event, data);\n });\n }\n }\n\n return {\n addEventHandler: addEventHandler,\n removeEventHandler: removeEventHandler,\n emit: emit\n };\n };\n\n}(window, document, Chartist));\n;/**\n * This module provides some basic prototype inheritance utilities.\n *\n * @module Chartist.Class\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n function listToArray(list) {\n var arr = [];\n if (list.length) {\n for (var i = 0; i < list.length; i++) {\n arr.push(list[i]);\n }\n }\n return arr;\n }\n\n /**\n * Method to extend from current prototype.\n *\n * @memberof Chartist.Class\n * @param {Object} properties The object that serves as definition for the prototype that gets created for the new class. This object should always contain a constructor property that is the desired constructor for the newly created class.\n * @param {Object} [superProtoOverride] By default extens will use the current class prototype or Chartist.class. With this parameter you can specify any super prototype that will be used.\n * @return {Function} Constructor function of the new class\n *\n * @example\n * var Fruit = Class.extend({\n * color: undefined,\n * sugar: undefined,\n *\n * constructor: function(color, sugar) {\n * this.color = color;\n * this.sugar = sugar;\n * },\n *\n * eat: function() {\n * this.sugar = 0;\n * return this;\n * }\n * });\n *\n * var Banana = Fruit.extend({\n * length: undefined,\n *\n * constructor: function(length, sugar) {\n * Banana.super.constructor.call(this, 'Yellow', sugar);\n * this.length = length;\n * }\n * });\n *\n * var banana = new Banana(20, 40);\n * console.log('banana instanceof Fruit', banana instanceof Fruit);\n * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana));\n * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype);\n * console.log(banana.sugar);\n * console.log(banana.eat().sugar);\n * console.log(banana.color);\n */\n function extend(properties, superProtoOverride) {\n var superProto = superProtoOverride || this.prototype || Chartist.Class;\n var proto = Object.create(superProto);\n\n Chartist.Class.cloneDefinitions(proto, properties);\n\n var constr = function() {\n var fn = proto.constructor || function () {},\n instance;\n\n // If this is linked to the Chartist namespace the constructor was not called with new\n // To provide a fallback we will instantiate here and return the instance\n instance = this === Chartist ? Object.create(proto) : this;\n fn.apply(instance, Array.prototype.slice.call(arguments, 0));\n\n // If this constructor was not called with new we need to return the instance\n // This will not harm when the constructor has been called with new as the returned value is ignored\n return instance;\n };\n\n constr.prototype = proto;\n constr.super = superProto;\n constr.extend = this.extend;\n\n return constr;\n }\n\n // Variable argument list clones args > 0 into args[0] and retruns modified args[0]\n function cloneDefinitions() {\n var args = listToArray(arguments);\n var target = args[0];\n\n args.splice(1, args.length - 1).forEach(function (source) {\n Object.getOwnPropertyNames(source).forEach(function (propName) {\n // If this property already exist in target we delete it first\n delete target[propName];\n // Define the property with the descriptor from source\n Object.defineProperty(target, propName,\n Object.getOwnPropertyDescriptor(source, propName));\n });\n });\n\n return target;\n }\n\n Chartist.Class = {\n extend: extend,\n cloneDefinitions: cloneDefinitions\n };\n\n}(window, document, Chartist));\n;/**\n * Base for all chart types. The methods in Chartist.Base are inherited to all chart types.\n *\n * @module Chartist.Base\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance.\n // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not\n // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage.\n // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html\n // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj\n // The problem is with the label offsets that can't be converted into percentage and affecting the chart container\n /**\n * Updates the chart which currently does a full reconstruction of the SVG DOM\n *\n * @param {Object} [data] Optional data you'd like to set for the chart before it will update. If not specified the update method will use the data that is already configured with the chart.\n * @param {Object} [options] Optional options you'd like to add to the previous options for the chart before it will update. If not specified the update method will use the options that have been already configured with the chart.\n * @param {Boolean} [override] If set to true, the passed options will be used to extend the options that have been configured already. Otherwise the chart default options will be used as the base\n * @memberof Chartist.Base\n */\n function update(data, options, override) {\n if(data) {\n this.data = data || {};\n this.data.labels = this.data.labels || [];\n this.data.series = this.data.series || [];\n // Event for data transformation that allows to manipulate the data before it gets rendered in the charts\n this.eventEmitter.emit('data', {\n type: 'update',\n data: this.data\n });\n }\n\n if(options) {\n this.options = Chartist.extend({}, override ? this.options : this.defaultOptions, options);\n\n // If chartist was not initialized yet, we just set the options and leave the rest to the initialization\n // Otherwise we re-create the optionsProvider at this point\n if(!this.initializeTimeoutId) {\n this.optionsProvider.removeMediaQueryListeners();\n this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n }\n }\n\n // Only re-created the chart if it has been initialized yet\n if(!this.initializeTimeoutId) {\n this.createChart(this.optionsProvider.getCurrentOptions());\n }\n\n // Return a reference to the chart object to chain up calls\n return this;\n }\n\n /**\n * This method can be called on the API object of each chart and will un-register all event listeners that were added to other components. This currently includes a window.resize listener as well as media query listeners if any responsive options have been provided. Use this function if you need to destroy and recreate Chartist charts dynamically.\n *\n * @memberof Chartist.Base\n */\n function detach() {\n // Only detach if initialization already occurred on this chart. If this chart still hasn't initialized (therefore\n // the initializationTimeoutId is still a valid timeout reference, we will clear the timeout\n if(!this.initializeTimeoutId) {\n window.removeEventListener('resize', this.resizeListener);\n this.optionsProvider.removeMediaQueryListeners();\n } else {\n window.clearTimeout(this.initializeTimeoutId);\n }\n\n return this;\n }\n\n /**\n * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop.\n *\n * @memberof Chartist.Base\n * @param {String} event Name of the event. Check the examples for supported events.\n * @param {Function} handler The handler function that will be called when an event with the given name was emitted. This function will receive a data argument which contains event data. See the example for more details.\n */\n function on(event, handler) {\n this.eventEmitter.addEventHandler(event, handler);\n return this;\n }\n\n /**\n * Use this function to un-register event handlers. If the handler function parameter is omitted all handlers for the given event will be un-registered.\n *\n * @memberof Chartist.Base\n * @param {String} event Name of the event for which a handler should be removed\n * @param {Function} [handler] The handler function that that was previously used to register a new event handler. This handler will be removed from the event handler list. If this parameter is omitted then all event handlers for the given event are removed from the list.\n */\n function off(event, handler) {\n this.eventEmitter.removeEventHandler(event, handler);\n return this;\n }\n\n function initialize() {\n // Add window resize listener that re-creates the chart\n window.addEventListener('resize', this.resizeListener);\n\n // Obtain current options based on matching media queries (if responsive options are given)\n // This will also register a listener that is re-creating the chart based on media changes\n this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);\n // Register options change listener that will trigger a chart update\n this.eventEmitter.addEventHandler('optionsChanged', function() {\n this.update();\n }.bind(this));\n\n // Before the first chart creation we need to register us with all plugins that are configured\n // Initialize all relevant plugins with our chart object and the plugin options specified in the config\n if(this.options.plugins) {\n this.options.plugins.forEach(function(plugin) {\n if(plugin instanceof Array) {\n plugin[0](this, plugin[1]);\n } else {\n plugin(this);\n }\n }.bind(this));\n }\n\n // Event for data transformation that allows to manipulate the data before it gets rendered in the charts\n this.eventEmitter.emit('data', {\n type: 'initial',\n data: this.data\n });\n\n // Create the first chart\n this.createChart(this.optionsProvider.getCurrentOptions());\n\n // As chart is initialized from the event loop now we can reset our timeout reference\n // This is important if the chart gets initialized on the same element twice\n this.initializeTimeoutId = undefined;\n }\n\n /**\n * Constructor of chart base class.\n *\n * @param query\n * @param data\n * @param defaultOptions\n * @param options\n * @param responsiveOptions\n * @constructor\n */\n function Base(query, data, defaultOptions, options, responsiveOptions) {\n this.container = Chartist.querySelector(query);\n this.data = data || {};\n this.data.labels = this.data.labels || [];\n this.data.series = this.data.series || [];\n this.defaultOptions = defaultOptions;\n this.options = options;\n this.responsiveOptions = responsiveOptions;\n this.eventEmitter = Chartist.EventEmitter();\n this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility');\n this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute');\n this.resizeListener = function resizeListener(){\n this.update();\n }.bind(this);\n\n if(this.container) {\n // If chartist was already initialized in this container we are detaching all event listeners first\n if(this.container.__chartist__) {\n this.container.__chartist__.detach();\n }\n\n this.container.__chartist__ = this;\n }\n\n // Using event loop for first draw to make it possible to register event listeners in the same call stack where\n // the chart was created.\n this.initializeTimeoutId = setTimeout(initialize.bind(this), 0);\n }\n\n // Creating the chart base class\n Chartist.Base = Chartist.Class.extend({\n constructor: Base,\n optionsProvider: undefined,\n container: undefined,\n svg: undefined,\n eventEmitter: undefined,\n createChart: function() {\n throw new Error('Base chart type can\\'t be instantiated!');\n },\n update: update,\n detach: detach,\n on: on,\n off: off,\n version: Chartist.version,\n supportsForeignObject: false\n });\n\n}(window, document, Chartist));\n;/**\n * Chartist SVG module for simple SVG DOM abstraction\n *\n * @module Chartist.Svg\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n /**\n * Chartist.Svg creates a new SVG object wrapper with a starting element. You can use the wrapper to fluently create sub-elements and modify them.\n *\n * @memberof Chartist.Svg\n * @constructor\n * @param {String|Element} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg\n * @param {Object} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added.\n * @param {String} className This class or class list will be added to the SVG element\n * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child\n * @param {Boolean} insertFirst If this param is set to true in conjunction with a parent element the newly created element will be added as first child element in the parent element\n */\n function Svg(name, attributes, className, parent, insertFirst) {\n // If Svg is getting called with an SVG element we just return the wrapper\n if(name instanceof Element) {\n this._node = name;\n } else {\n this._node = document.createElementNS(Chartist.namespaces.svg, name);\n\n // If this is an SVG element created then custom namespace\n if(name === 'svg') {\n this.attr({\n 'xmlns:ct': Chartist.namespaces.ct\n });\n }\n }\n\n if(attributes) {\n this.attr(attributes);\n }\n\n if(className) {\n this.addClass(className);\n }\n\n if(parent) {\n if (insertFirst && parent._node.firstChild) {\n parent._node.insertBefore(this._node, parent._node.firstChild);\n } else {\n parent._node.appendChild(this._node);\n }\n }\n }\n\n /**\n * Set attributes on the current SVG element of the wrapper you're currently working on.\n *\n * @memberof Chartist.Svg\n * @param {Object|String} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added. If this parameter is a String then the function is used as a getter and will return the attribute value.\n * @param {String} [ns] If specified, the attribute will be obtained using getAttributeNs. In order to write namepsaced attributes you can use the namespace:attribute notation within the attributes object.\n * @return {Object|String} The current wrapper object will be returned so it can be used for chaining or the attribute value if used as getter function.\n */\n function attr(attributes, ns) {\n if(typeof attributes === 'string') {\n if(ns) {\n return this._node.getAttributeNS(ns, attributes);\n } else {\n return this._node.getAttribute(attributes);\n }\n }\n\n Object.keys(attributes).forEach(function(key) {\n // If the attribute value is undefined we can skip this one\n if(attributes[key] === undefined) {\n return;\n }\n\n if (key.indexOf(':') !== -1) {\n var namespacedAttribute = key.split(':');\n this._node.setAttributeNS(Chartist.namespaces[namespacedAttribute[0]], key, attributes[key]);\n } else {\n this._node.setAttribute(key, attributes[key]);\n }\n }.bind(this));\n\n return this;\n }\n\n /**\n * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily.\n *\n * @memberof Chartist.Svg\n * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper\n * @param {Object} [attributes] An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added.\n * @param {String} [className] This class or class list will be added to the SVG element\n * @param {Boolean} [insertFirst] If this param is set to true in conjunction with a parent element the newly created element will be added as first child element in the parent element\n * @return {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data\n */\n function elem(name, attributes, className, insertFirst) {\n return new Chartist.Svg(name, attributes, className, this, insertFirst);\n }\n\n /**\n * Returns the parent Chartist.SVG wrapper object\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} Returns a Chartist.Svg wrapper around the parent node of the current node. If the parent node is not existing or it's not an SVG node then this function will return null.\n */\n function parent() {\n return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null;\n }\n\n /**\n * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree.\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element\n */\n function root() {\n var node = this._node;\n while(node.nodeName !== 'svg') {\n node = node.parentNode;\n }\n return new Chartist.Svg(node);\n }\n\n /**\n * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper.\n *\n * @memberof Chartist.Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found\n */\n function querySelector(selector) {\n var foundNode = this._node.querySelector(selector);\n return foundNode ? new Chartist.Svg(foundNode) : null;\n }\n\n /**\n * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper.\n *\n * @memberof Chartist.Svg\n * @param {String} selector A CSS selector that is used to query for child SVG elements\n * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found\n */\n function querySelectorAll(selector) {\n var foundNodes = this._node.querySelectorAll(selector);\n return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null;\n }\n\n /**\n * Returns the underlying SVG node for the current element.\n *\n * @memberof Chartist.Svg\n * @returns {Node}\n */\n function getNode() {\n return this._node;\n }\n\n /**\n * This method creates a foreignObject (see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject) that allows to embed HTML content into a SVG graphic. With the help of foreignObjects you can enable the usage of regular HTML elements inside of SVG where they are subject for SVG positioning and transformation but the Browser will use the HTML rendering capabilities for the containing DOM.\n *\n * @memberof Chartist.Svg\n * @param {Node|String} content The DOM Node, or HTML string that will be converted to a DOM Node, that is then placed into and wrapped by the foreignObject\n * @param {String} [attributes] An object with properties that will be added as attributes to the foreignObject element that is created. Attributes with undefined values will not be added.\n * @param {String} [className] This class or class list will be added to the SVG element\n * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child\n * @return {Chartist.Svg} New wrapper object that wraps the foreignObject element\n */\n function foreignObject(content, attributes, className, insertFirst) {\n // If content is string then we convert it to DOM\n // TODO: Handle case where content is not a string nor a DOM Node\n if(typeof content === 'string') {\n var container = document.createElement('div');\n container.innerHTML = content;\n content = container.firstChild;\n }\n\n // Adding namespace to content element\n content.setAttribute('xmlns', Chartist.namespaces.xmlns);\n\n // Creating the foreignObject without required extension attribute (as described here\n // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement)\n var fnObj = this.elem('foreignObject', attributes, className, insertFirst);\n\n // Add content to foreignObjectElement\n fnObj._node.appendChild(content);\n\n return fnObj;\n }\n\n /**\n * This method adds a new text element to the current Chartist.Svg wrapper.\n *\n * @memberof Chartist.Svg\n * @param {String} t The text that should be added to the text element that is created\n * @return {Chartist.Svg} The same wrapper object that was used to add the newly created element\n */\n function text(t) {\n this._node.appendChild(document.createTextNode(t));\n return this;\n }\n\n /**\n * This method will clear all child nodes of the current wrapper object.\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} The same wrapper object that got emptied\n */\n function empty() {\n while (this._node.firstChild) {\n this._node.removeChild(this._node.firstChild);\n }\n\n return this;\n }\n\n /**\n * This method will cause the current wrapper to remove itself from its parent wrapper. Use this method if you'd like to get rid of an element in a given DOM structure.\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} The parent wrapper object of the element that got removed\n */\n function remove() {\n this._node.parentNode.removeChild(this._node);\n return this.parent();\n }\n\n /**\n * This method will replace the element with a new element that can be created outside of the current DOM.\n *\n * @memberof Chartist.Svg\n * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object\n * @return {Chartist.Svg} The wrapper of the new element\n */\n function replace(newElement) {\n this._node.parentNode.replaceChild(newElement._node, this._node);\n return newElement;\n }\n\n /**\n * This method will append an element to the current element as a child.\n *\n * @memberof Chartist.Svg\n * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child\n * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child\n * @return {Chartist.Svg} The wrapper of the appended object\n */\n function append(element, insertFirst) {\n if(insertFirst && this._node.firstChild) {\n this._node.insertBefore(element._node, this._node.firstChild);\n } else {\n this._node.appendChild(element._node);\n }\n\n return this;\n }\n\n /**\n * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further.\n *\n * @memberof Chartist.Svg\n * @return {Array} A list of classes or an empty array if there are no classes on the current element\n */\n function classes() {\n return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\\s+/) : [];\n }\n\n /**\n * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once.\n *\n * @memberof Chartist.Svg\n * @param {String} names A white space separated list of class names\n * @return {Chartist.Svg} The wrapper of the current element\n */\n function addClass(names) {\n this._node.setAttribute('class',\n this.classes(this._node)\n .concat(names.trim().split(/\\s+/))\n .filter(function(elem, pos, self) {\n return self.indexOf(elem) === pos;\n }).join(' ')\n );\n\n return this;\n }\n\n /**\n * Removes one or a space separated list of classes from the current element.\n *\n * @memberof Chartist.Svg\n * @param {String} names A white space separated list of class names\n * @return {Chartist.Svg} The wrapper of the current element\n */\n function removeClass(names) {\n var removedClasses = names.trim().split(/\\s+/);\n\n this._node.setAttribute('class', this.classes(this._node).filter(function(name) {\n return removedClasses.indexOf(name) === -1;\n }).join(' '));\n\n return this;\n }\n\n /**\n * Removes all classes from the current element.\n *\n * @memberof Chartist.Svg\n * @return {Chartist.Svg} The wrapper of the current element\n */\n function removeAllClasses() {\n this._node.setAttribute('class', '');\n\n return this;\n }\n\n /**\n * Get element height using `getBoundingClientRect`\n *\n * @memberof Chartist.Svg\n * @return {Number} The elements height in pixels\n */\n function height() {\n return this._node.getBoundingClientRect().height;\n }\n\n /**\n * Get element width using `getBoundingClientRect`\n *\n * @memberof Chartist.Core\n * @return {Number} The elements width in pixels\n */\n function width() {\n return this._node.getBoundingClientRect().width;\n }\n\n /**\n * The animate function lets you animate the current element with SMIL animations. You can add animations for multiple attributes at the same time by using an animation definition object. This object should contain SMIL animation attributes. Please refer to http://www.w3.org/TR/SVG/animate.html for a detailed specification about the available animation attributes. Additionally an easing property can be passed in the animation definition object. This can be a string with a name of an easing function in `Chartist.Svg.Easing` or an array with four numbers specifying a cubic Bézier curve.\n * **An animations object could look like this:**\n * ```javascript\n * element.animate({\n * opacity: {\n * dur: 1000,\n * from: 0,\n * to: 1\n * },\n * x1: {\n * dur: '1000ms',\n * from: 100,\n * to: 200,\n * easing: 'easeOutQuart'\n * },\n * y1: {\n * dur: '2s',\n * from: 0,\n * to: 100\n * }\n * });\n * ```\n * **Automatic unit conversion**\n * For the `dur` and the `begin` animate attribute you can also omit a unit by passing a number. The number will automatically be converted to milli seconds.\n * **Guided mode**\n * The default behavior of SMIL animations with offset using the `begin` attribute is that the attribute will keep it's original value until the animation starts. Mostly this behavior is not desired as you'd like to have your element attributes already initialized with the animation `from` value even before the animation starts. Also if you don't specify `fill=\"freeze\"` on an animate element or if you delete the animation after it's done (which is done in guided mode) the attribute will switch back to the initial value. This behavior is also not desired when performing simple one-time animations. For one-time animations you'd want to trigger animations immediately instead of relative to the document begin time. That's why in guided mode Chartist.Svg will also use the `begin` property to schedule a timeout and manually start the animation after the timeout. If you're using multiple SMIL definition objects for an attribute (in an array), guided mode will be disabled for this attribute, even if you explicitly enabled it.\n * If guided mode is enabled the following behavior is added:\n * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation\n * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation)\n * - The animate element will be forced to use `fill=\"freeze\"`\n * - The animation will be triggered with `beginElement()` in a timeout where `begin` of the definition object is interpreted in milli seconds. If no `begin` was specified the timeout is triggered immediately.\n * - After the animation the element attribute value will be set to the `to` value of the animation\n * - The animate element is deleted from the DOM\n *\n * @memberof Chartist.Svg\n * @param {Object} animations An animations object where the property keys are the attributes you'd like to animate. The properties should be objects again that contain the SMIL animation attributes (usually begin, dur, from, and to). The property begin and dur is auto converted (see Automatic unit conversion). You can also schedule multiple animations for the same attribute by passing an Array of SMIL definition objects. Attributes that contain an array of SMIL definition objects will not be executed in guided mode.\n * @param {Boolean} guided Specify if guided mode should be activated for this animation (see Guided mode). If not otherwise specified, guided mode will be activated.\n * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends.\n * @return {Chartist.Svg} The current element where the animation was added\n */\n function animate(animations, guided, eventEmitter) {\n if(guided === undefined) {\n guided = true;\n }\n\n Object.keys(animations).forEach(function createAnimateForAttributes(attribute) {\n\n function createAnimate(animationDefinition, guided) {\n var attributeProperties = {},\n animate,\n timeout,\n easing;\n\n // Check if an easing is specified in the definition object and delete it from the object as it will not\n // be part of the animate element attributes.\n if(animationDefinition.easing) {\n // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object\n easing = animationDefinition.easing instanceof Array ?\n animationDefinition.easing :\n Chartist.Svg.Easing[animationDefinition.easing];\n delete animationDefinition.easing;\n }\n\n // If numeric dur or begin was provided we assume milli seconds\n animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms');\n animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms');\n\n if(easing) {\n animationDefinition.calcMode = 'spline';\n animationDefinition.keySplines = easing.join(' ');\n animationDefinition.keyTimes = '0;1';\n }\n\n // Adding \"fill: freeze\" if we are in guided mode and set initial attribute values\n if(guided) {\n animationDefinition.fill = 'freeze';\n // Animated property on our element should already be set to the animation from value in guided mode\n attributeProperties[attribute] = animationDefinition.from;\n this.attr(attributeProperties);\n\n // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin\n // which needs to be in ms aside\n timeout = Chartist.quantity(animationDefinition.begin || 0).value;\n animationDefinition.begin = 'indefinite';\n }\n\n animate = this.elem('animate', Chartist.extend({\n attributeName: attribute\n }, animationDefinition));\n\n if(guided) {\n // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout\n setTimeout(function() {\n // If beginElement fails we set the animated attribute to the end position and remove the animate element\n // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in\n // the browser. (Currently FF 34 does not support animate elements in foreignObjects)\n try {\n animate._node.beginElement();\n } catch(err) {\n // Set animated attribute to current animated value\n attributeProperties[attribute] = animationDefinition.to;\n this.attr(attributeProperties);\n // Remove the animate element as it's no longer required\n animate.remove();\n }\n }.bind(this), timeout);\n }\n\n if(eventEmitter) {\n animate._node.addEventListener('beginEvent', function handleBeginEvent() {\n eventEmitter.emit('animationBegin', {\n element: this,\n animate: animate._node,\n params: animationDefinition\n });\n }.bind(this));\n }\n\n animate._node.addEventListener('endEvent', function handleEndEvent() {\n if(eventEmitter) {\n eventEmitter.emit('animationEnd', {\n element: this,\n animate: animate._node,\n params: animationDefinition\n });\n }\n\n if(guided) {\n // Set animated attribute to current animated value\n attributeProperties[attribute] = animationDefinition.to;\n this.attr(attributeProperties);\n // Remove the animate element as it's no longer required\n animate.remove();\n }\n }.bind(this));\n }\n\n // If current attribute is an array of definition objects we create an animate for each and disable guided mode\n if(animations[attribute] instanceof Array) {\n animations[attribute].forEach(function(animationDefinition) {\n createAnimate.bind(this)(animationDefinition, false);\n }.bind(this));\n } else {\n createAnimate.bind(this)(animations[attribute], guided);\n }\n\n }.bind(this));\n\n return this;\n }\n\n Chartist.Svg = Chartist.Class.extend({\n constructor: Svg,\n attr: attr,\n elem: elem,\n parent: parent,\n root: root,\n querySelector: querySelector,\n querySelectorAll: querySelectorAll,\n getNode: getNode,\n foreignObject: foreignObject,\n text: text,\n empty: empty,\n remove: remove,\n replace: replace,\n append: append,\n classes: classes,\n addClass: addClass,\n removeClass: removeClass,\n removeAllClasses: removeAllClasses,\n height: height,\n width: width,\n animate: animate\n });\n\n /**\n * This method checks for support of a given SVG feature like Extensibility, SVG-animation or the like. Check http://www.w3.org/TR/SVG11/feature for a detailed list.\n *\n * @memberof Chartist.Svg\n * @param {String} feature The SVG 1.1 feature that should be checked for support.\n * @return {Boolean} True of false if the feature is supported or not\n */\n Chartist.Svg.isSupported = function(feature) {\n return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#' + feature, '1.1');\n };\n\n /**\n * This Object contains some standard easing cubic bezier curves. Then can be used with their name in the `Chartist.Svg.animate`. You can also extend the list and use your own name in the `animate` function. Click the show code button to see the available bezier functions.\n *\n * @memberof Chartist.Svg\n */\n var easingCubicBeziers = {\n easeInSine: [0.47, 0, 0.745, 0.715],\n easeOutSine: [0.39, 0.575, 0.565, 1],\n easeInOutSine: [0.445, 0.05, 0.55, 0.95],\n easeInQuad: [0.55, 0.085, 0.68, 0.53],\n easeOutQuad: [0.25, 0.46, 0.45, 0.94],\n easeInOutQuad: [0.455, 0.03, 0.515, 0.955],\n easeInCubic: [0.55, 0.055, 0.675, 0.19],\n easeOutCubic: [0.215, 0.61, 0.355, 1],\n easeInOutCubic: [0.645, 0.045, 0.355, 1],\n easeInQuart: [0.895, 0.03, 0.685, 0.22],\n easeOutQuart: [0.165, 0.84, 0.44, 1],\n easeInOutQuart: [0.77, 0, 0.175, 1],\n easeInQuint: [0.755, 0.05, 0.855, 0.06],\n easeOutQuint: [0.23, 1, 0.32, 1],\n easeInOutQuint: [0.86, 0, 0.07, 1],\n easeInExpo: [0.95, 0.05, 0.795, 0.035],\n easeOutExpo: [0.19, 1, 0.22, 1],\n easeInOutExpo: [1, 0, 0, 1],\n easeInCirc: [0.6, 0.04, 0.98, 0.335],\n easeOutCirc: [0.075, 0.82, 0.165, 1],\n easeInOutCirc: [0.785, 0.135, 0.15, 0.86],\n easeInBack: [0.6, -0.28, 0.735, 0.045],\n easeOutBack: [0.175, 0.885, 0.32, 1.275],\n easeInOutBack: [0.68, -0.55, 0.265, 1.55]\n };\n\n Chartist.Svg.Easing = easingCubicBeziers;\n\n /**\n * This helper class is to wrap multiple `Chartist.Svg` elements into a list where you can call the `Chartist.Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Chartist.Svg` on multiple elements.\n * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`.\n *\n * @memberof Chartist.Svg\n * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll)\n * @constructor\n */\n function SvgList(nodeList) {\n var list = this;\n\n this.svgElements = [];\n for(var i = 0; i < nodeList.length; i++) {\n this.svgElements.push(new Chartist.Svg(nodeList[i]));\n }\n\n // Add delegation methods for Chartist.Svg\n Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) {\n return ['constructor',\n 'parent',\n 'querySelector',\n 'querySelectorAll',\n 'replace',\n 'append',\n 'classes',\n 'height',\n 'width'].indexOf(prototypeProperty) === -1;\n }).forEach(function(prototypeProperty) {\n list[prototypeProperty] = function() {\n var args = Array.prototype.slice.call(arguments, 0);\n list.svgElements.forEach(function(element) {\n Chartist.Svg.prototype[prototypeProperty].apply(element, args);\n });\n return list;\n };\n });\n }\n\n Chartist.Svg.List = Chartist.Class.extend({\n constructor: SvgList\n });\n}(window, document, Chartist));\n;/**\n * Chartist SVG path module for SVG path description creation and modification.\n *\n * @module Chartist.Svg.Path\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n /**\n * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported.\n *\n * @memberof Chartist.Svg.Path\n * @type {Object}\n */\n var elementDescriptions = {\n m: ['x', 'y'],\n l: ['x', 'y'],\n c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'],\n a: ['rx', 'ry', 'xAr', 'lAf', 'sf', 'x', 'y']\n };\n\n /**\n * Default options for newly created SVG path objects.\n *\n * @memberof Chartist.Svg.Path\n * @type {Object}\n */\n var defaultOptions = {\n // The accuracy in digit count after the decimal point. This will be used to round numbers in the SVG path. If this option is set to false then no rounding will be performed.\n accuracy: 3\n };\n\n function element(command, params, pathElements, pos, relative, data) {\n var pathElement = Chartist.extend({\n command: relative ? command.toLowerCase() : command.toUpperCase()\n }, params, data ? { data: data } : {} );\n\n pathElements.splice(pos, 0, pathElement);\n }\n\n function forEachParam(pathElements, cb) {\n pathElements.forEach(function(pathElement, pathElementIndex) {\n elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) {\n cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements);\n });\n });\n }\n\n /**\n * Used to construct a new path object.\n *\n * @memberof Chartist.Svg.Path\n * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end)\n * @param {Object} options Options object that overrides the default objects. See default options for more details.\n * @constructor\n */\n function SvgPath(close, options) {\n this.pathElements = [];\n this.pos = 0;\n this.close = close;\n this.options = Chartist.extend({}, defaultOptions, options);\n }\n\n /**\n * Gets or sets the current position (cursor) inside of the path. You can move around the cursor freely but limited to 0 or the count of existing elements. All modifications with element functions will insert new elements at the position of this cursor.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array.\n * @return {Chartist.Svg.Path|Number} If the position parameter was passed then the return value will be the path object for easy call chaining. If no position parameter was passed then the current position is returned.\n */\n function position(pos) {\n if(pos !== undefined) {\n this.pos = Math.max(0, Math.min(this.pathElements.length, pos));\n return this;\n } else {\n return this.pos;\n }\n }\n\n /**\n * Removes elements from the path starting at the current position.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} count Number of path elements that should be removed from the current position.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function remove(count) {\n this.pathElements.splice(this.pos, count);\n return this;\n }\n\n /**\n * Use this function to add a new move SVG path element.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x The x coordinate for the move element.\n * @param {Number} y The y coordinate for the move element.\n * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter)\n * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function move(x, y, relative, data) {\n element('M', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative, data);\n return this;\n }\n\n /**\n * Use this function to add a new line SVG path element.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x The x coordinate for the line element.\n * @param {Number} y The y coordinate for the line element.\n * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter)\n * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function line(x, y, relative, data) {\n element('L', {\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative, data);\n return this;\n }\n\n /**\n * Use this function to add a new curve SVG path element.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x1 The x coordinate for the first control point of the bezier curve.\n * @param {Number} y1 The y coordinate for the first control point of the bezier curve.\n * @param {Number} x2 The x coordinate for the second control point of the bezier curve.\n * @param {Number} y2 The y coordinate for the second control point of the bezier curve.\n * @param {Number} x The x coordinate for the target point of the curve element.\n * @param {Number} y The y coordinate for the target point of the curve element.\n * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter)\n * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function curve(x1, y1, x2, y2, x, y, relative, data) {\n element('C', {\n x1: +x1,\n y1: +y1,\n x2: +x2,\n y2: +y2,\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative, data);\n return this;\n }\n\n /**\n * Use this function to add a new non-bezier curve SVG path element.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} rx The radius to be used for the x-axis of the arc.\n * @param {Number} ry The radius to be used for the y-axis of the arc.\n * @param {Number} xAr Defines the orientation of the arc\n * @param {Number} lAf Large arc flag\n * @param {Number} sf Sweep flag\n * @param {Number} x The x coordinate for the target point of the curve element.\n * @param {Number} y The y coordinate for the target point of the curve element.\n * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter)\n * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function arc(rx, ry, xAr, lAf, sf, x, y, relative, data) {\n element('A', {\n rx: +rx,\n ry: +ry,\n xAr: +xAr,\n lAf: +lAf,\n sf: +sf,\n x: +x,\n y: +y\n }, this.pathElements, this.pos++, relative, data);\n return this;\n }\n\n /**\n * Parses an SVG path seen in the d attribute of path elements, and inserts the parsed elements into the existing path object at the current cursor position. Any closing path indicators (Z at the end of the path) will be ignored by the parser as this is provided by the close option in the options of the path object.\n *\n * @memberof Chartist.Svg.Path\n * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function parse(path) {\n // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']]\n var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2')\n .replace(/([0-9])([A-Za-z])/g, '$1 $2')\n .split(/[\\s,]+/)\n .reduce(function(result, element) {\n if(element.match(/[A-Za-z]/)) {\n result.push([]);\n }\n\n result[result.length - 1].push(element);\n return result;\n }, []);\n\n // If this is a closed path we remove the Z at the end because this is determined by the close option\n if(chunks[chunks.length - 1][0].toUpperCase() === 'Z') {\n chunks.pop();\n }\n\n // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters\n // For example {command: 'M', x: '10', y: '10'}\n var elements = chunks.map(function(chunk) {\n var command = chunk.shift(),\n description = elementDescriptions[command.toLowerCase()];\n\n return Chartist.extend({\n command: command\n }, description.reduce(function(result, paramName, index) {\n result[paramName] = +chunk[index];\n return result;\n }, {}));\n });\n\n // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position\n var spliceArgs = [this.pos, 0];\n Array.prototype.push.apply(spliceArgs, elements);\n Array.prototype.splice.apply(this.pathElements, spliceArgs);\n // Increase the internal position by the element count\n this.pos += elements.length;\n\n return this;\n }\n\n /**\n * This function renders to current SVG path object into a final SVG string that can be used in the d attribute of SVG path elements. It uses the accuracy option to round big decimals. If the close parameter was set in the constructor of this path object then a path closing Z will be appended to the output string.\n *\n * @memberof Chartist.Svg.Path\n * @return {String}\n */\n function stringify() {\n var accuracyMultiplier = Math.pow(10, this.options.accuracy);\n\n return this.pathElements.reduce(function(path, pathElement) {\n var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) {\n return this.options.accuracy ?\n (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) :\n pathElement[paramName];\n }.bind(this));\n\n return path + pathElement.command + params.join(',');\n }.bind(this), '') + (this.close ? 'Z' : '');\n }\n\n /**\n * Scales all elements in the current SVG path object. There is an individual parameter for each coordinate. Scaling will also be done for control points of curves, affecting the given coordinate.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements.\n * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function scale(x, y) {\n forEachParam(this.pathElements, function(pathElement, paramName) {\n pathElement[paramName] *= paramName[0] === 'x' ? x : y;\n });\n return this;\n }\n\n /**\n * Translates all elements in the current SVG path object. The translation is relative and there is an individual parameter for each coordinate. Translation will also be done for control points of curves, affecting the given coordinate.\n *\n * @memberof Chartist.Svg.Path\n * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements.\n * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function translate(x, y) {\n forEachParam(this.pathElements, function(pathElement, paramName) {\n pathElement[paramName] += paramName[0] === 'x' ? x : y;\n });\n return this;\n }\n\n /**\n * This function will run over all existing path elements and then loop over their attributes. The callback function will be called for every path element attribute that exists in the current path.\n * The method signature of the callback function looks like this:\n * ```javascript\n * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements)\n * ```\n * If something else than undefined is returned by the callback function, this value will be used to replace the old value. This allows you to build custom transformations of path objects that can't be achieved using the basic transformation functions scale and translate.\n *\n * @memberof Chartist.Svg.Path\n * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description.\n * @return {Chartist.Svg.Path} The current path object for easy call chaining.\n */\n function transform(transformFnc) {\n forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) {\n var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements);\n if(transformed || transformed === 0) {\n pathElement[paramName] = transformed;\n }\n });\n return this;\n }\n\n /**\n * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned.\n *\n * @memberof Chartist.Svg.Path\n * @param {Boolean} [close] Optional option to set the new cloned path to closed. If not specified or false, the original path close option will be used.\n * @return {Chartist.Svg.Path}\n */\n function clone(close) {\n var c = new Chartist.Svg.Path(close || this.close);\n c.pos = this.pos;\n c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) {\n return Chartist.extend({}, pathElement);\n });\n c.options = Chartist.extend({}, this.options);\n return c;\n }\n\n /**\n * Split a Svg.Path object by a specific command in the path chain. The path chain will be split and an array of newly created paths objects will be returned. This is useful if you'd like to split an SVG path by it's move commands, for example, in order to isolate chunks of drawings.\n *\n * @memberof Chartist.Svg.Path\n * @param {String} command The command you'd like to use to split the path\n * @return {Array}\n */\n function splitByCommand(command) {\n var split = [\n new Chartist.Svg.Path()\n ];\n\n this.pathElements.forEach(function(pathElement) {\n if(pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) {\n split.push(new Chartist.Svg.Path());\n }\n\n split[split.length - 1].pathElements.push(pathElement);\n });\n\n return split;\n }\n\n /**\n * This static function on `Chartist.Svg.Path` is joining multiple paths together into one paths.\n *\n * @memberof Chartist.Svg.Path\n * @param {Array} paths A list of paths to be joined together. The order is important.\n * @param {boolean} close If the newly created path should be a closed path\n * @param {Object} options Path options for the newly created path.\n * @return {Chartist.Svg.Path}\n */\n\n function join(paths, close, options) {\n var joinedPath = new Chartist.Svg.Path(close, options);\n for(var i = 0; i < paths.length; i++) {\n var path = paths[i];\n for(var j = 0; j < path.pathElements.length; j++) {\n joinedPath.pathElements.push(path.pathElements[j]);\n }\n }\n return joinedPath;\n }\n\n Chartist.Svg.Path = Chartist.Class.extend({\n constructor: SvgPath,\n position: position,\n remove: remove,\n move: move,\n line: line,\n curve: curve,\n arc: arc,\n scale: scale,\n translate: translate,\n transform: transform,\n parse: parse,\n stringify: stringify,\n clone: clone,\n splitByCommand: splitByCommand\n });\n\n Chartist.Svg.Path.elementDescriptions = elementDescriptions;\n Chartist.Svg.Path.join = join;\n}(window, document, Chartist));\n;/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n var axisUnits = {\n x: {\n pos: 'x',\n len: 'width',\n dir: 'horizontal',\n rectStart: 'x1',\n rectEnd: 'x2',\n rectOffset: 'y2'\n },\n y: {\n pos: 'y',\n len: 'height',\n dir: 'vertical',\n rectStart: 'y2',\n rectEnd: 'y1',\n rectOffset: 'x1'\n }\n };\n\n function Axis(units, chartRect, ticks, options) {\n this.units = units;\n this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x;\n this.chartRect = chartRect;\n this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart];\n this.gridOffset = chartRect[units.rectOffset];\n this.ticks = ticks;\n this.options = options;\n }\n\n function createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) {\n var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()];\n var projectedValues = this.ticks.map(this.projectValue.bind(this));\n var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc);\n\n projectedValues.forEach(function(projectedValue, index) {\n var labelOffset = {\n x: 0,\n y: 0\n };\n\n // TODO: Find better solution for solving this problem\n // Calculate how much space we have available for the label\n var labelLength;\n if(projectedValues[index + 1]) {\n // If we still have one label ahead, we can calculate the distance to the next tick / label\n labelLength = projectedValues[index + 1] - projectedValue;\n } else {\n // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to\n // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will\n // still be visible inside of the chart padding.\n labelLength = Math.max(this.axisLength - projectedValue, 30);\n }\n\n // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)\n if(Chartist.isFalseyButZero(labelValues[index]) && labelValues[index] !== '') {\n return;\n }\n\n // Transform to global coordinates using the chartRect\n // We also need to set the label offset for the createLabel function\n if(this.units.pos === 'x') {\n projectedValue = this.chartRect.x1 + projectedValue;\n labelOffset.x = chartOptions.axisX.labelOffset.x;\n\n // If the labels should be positioned in start position (top side for vertical axis) we need to set a\n // different offset as for positioned with end (bottom)\n if(chartOptions.axisX.position === 'start') {\n labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n } else {\n labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20);\n }\n } else {\n projectedValue = this.chartRect.y1 - projectedValue;\n labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0);\n\n // If the labels should be positioned in start position (left side for horizontal axis) we need to set a\n // different offset as for positioned with end (right side)\n if(chartOptions.axisY.position === 'start') {\n labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10;\n } else {\n labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10;\n }\n }\n\n if(axisOptions.showGrid) {\n Chartist.createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [\n chartOptions.classNames.grid,\n chartOptions.classNames[this.units.dir]\n ], eventEmitter);\n }\n\n if(axisOptions.showLabel) {\n Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [\n chartOptions.classNames.label,\n chartOptions.classNames[this.units.dir],\n (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end'])\n ], useForeignObject, eventEmitter);\n }\n }.bind(this));\n }\n\n Chartist.Axis = Chartist.Class.extend({\n constructor: Axis,\n createGridAndLabels: createGridAndLabels,\n projectValue: function(value, index, data) {\n throw new Error('Base axis can\\'t be instantiated!');\n }\n });\n\n Chartist.Axis.units = axisUnits;\n\n}(window, document, Chartist));\n;/**\n * The auto scale axis uses standard linear scale projection of values along an axis. It uses order of magnitude to find a scale automatically and evaluates the available space in order to find the perfect amount of ticks for your chart.\n * **Options**\n * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.\n * ```javascript\n * var options = {\n * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored\n * high: 100,\n * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored\n * low: 0,\n * // This option will be used when finding the right scale division settings. The amount of ticks on the scale will be determined so that as many ticks as possible will be displayed, while not violating this minimum required space (in pixel).\n * scaleMinSpace: 20,\n * // Can be set to true or false. If set to true, the scale will be generated with whole numbers only.\n * onlyInteger: true,\n * // The reference value can be used to make sure that this value will always be on the chart. This is especially useful on bipolar charts where the bipolar center always needs to be part of the chart.\n * referenceValue: 5\n * };\n * ```\n *\n * @module Chartist.AutoScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function AutoScaleAxis(axisUnit, data, chartRect, options) {\n // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options\n var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos);\n this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger);\n this.range = {\n min: this.bounds.min,\n max: this.bounds.max\n };\n\n Chartist.AutoScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n this.bounds.values,\n options);\n }\n\n function projectValue(value) {\n return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range;\n }\n\n Chartist.AutoScaleAxis = Chartist.Axis.extend({\n constructor: AutoScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * The fixed scale axis uses standard linear projection of values along an axis. It makes use of a divisor option to divide the range provided from the minimum and maximum value or the options high and low that will override the computed minimum and maximum.\n * **Options**\n * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.\n * ```javascript\n * var options = {\n * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored\n * high: 100,\n * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored\n * low: 0,\n * // If specified then the value range determined from minimum to maximum (or low and high) will be divided by this number and ticks will be generated at those division points. The default divisor is 1.\n * divisor: 4,\n * // If ticks is explicitly set, then the axis will not compute the ticks with the divisor, but directly use the data in ticks to determine at what points on the axis a tick need to be generated.\n * ticks: [1, 10, 20, 30]\n * };\n * ```\n *\n * @module Chartist.FixedScaleAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function FixedScaleAxis(axisUnit, data, chartRect, options) {\n var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos);\n this.divisor = options.divisor || 1;\n this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) {\n return highLow.low + (highLow.high - highLow.low) / this.divisor * index;\n }.bind(this));\n this.ticks.sort(function(a, b) {\n return a - b;\n });\n this.range = {\n min: highLow.low,\n max: highLow.high\n };\n\n Chartist.FixedScaleAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n this.ticks,\n options);\n\n this.stepLength = this.axisLength / this.divisor;\n }\n\n function projectValue(value) {\n return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min);\n }\n\n Chartist.FixedScaleAxis = Chartist.Axis.extend({\n constructor: FixedScaleAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * The step axis for step based charts like bar chart or step based line charts. It uses a fixed amount of ticks that will be equally distributed across the whole axis length. The projection is done using the index of the data value rather than the value itself and therefore it's only useful for distribution purpose.\n * **Options**\n * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.\n * ```javascript\n * var options = {\n * // Ticks to be used to distribute across the axis length. As this axis type relies on the index of the value rather than the value, arbitrary data that can be converted to a string can be used as ticks.\n * ticks: ['One', 'Two', 'Three'],\n * // If set to true the full width will be used to distribute the values where the last value will be at the maximum of the axis length. If false the spaces between the ticks will be evenly distributed instead.\n * stretch: true\n * };\n * ```\n *\n * @module Chartist.StepAxis\n */\n/* global Chartist */\n(function (window, document, Chartist) {\n 'use strict';\n\n function StepAxis(axisUnit, data, chartRect, options) {\n Chartist.StepAxis.super.constructor.call(this,\n axisUnit,\n chartRect,\n options.ticks,\n options);\n\n var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0));\n this.stepLength = this.axisLength / calc;\n }\n\n function projectValue(value, index) {\n return this.stepLength * index;\n }\n\n Chartist.StepAxis = Chartist.Axis.extend({\n constructor: StepAxis,\n projectValue: projectValue\n });\n\n}(window, document, Chartist));\n;/**\n * The Chartist line chart can be used to draw Line or Scatter charts. If used in the browser you can access the global `Chartist` namespace where you find the `Line` function as a main entry point.\n *\n * For examples on how to use the line chart please check the examples of the `Chartist.Line` method.\n *\n * @module Chartist.Line\n */\n/* global Chartist */\n(function(window, document, Chartist){\n 'use strict';\n\n /**\n * Default options in line charts. Expand the code view to see a detailed list of options with comments.\n *\n * @memberof Chartist.Line\n */\n var defaultOptions = {\n // Options for X-Axis\n axisX: {\n // The offset of the labels to the chart area\n offset: 30,\n // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.\n position: 'end',\n // Allows you to correct label positioning on this axis by positive or negative x and y offset.\n labelOffset: {\n x: 0,\n y: 0\n },\n // If labels should be shown or not\n showLabel: true,\n // If the axis grid should be drawn or not\n showGrid: true,\n // Interpolation function that allows you to intercept the value from the axis label\n labelInterpolationFnc: Chartist.noop,\n // Set the axis type to be used to project values on this axis. If not defined, Chartist.StepAxis will be used for the X-Axis, where the ticks option will be set to the labels in the data and the stretch option will be set to the global fullWidth option. This type can be changed to any axis constructor available (e.g. Chartist.FixedScaleAxis), where all axis options should be present here.\n type: undefined\n },\n // Options for Y-Axis\n axisY: {\n // The offset of the labels to the chart area\n offset: 40,\n // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.\n position: 'start',\n // Allows you to correct label positioning on this axis by positive or negative x and y offset.\n labelOffset: {\n x: 0,\n y: 0\n },\n // If labels should be shown or not\n showLabel: true,\n // If the axis grid should be drawn or not\n showGrid: true,\n // Interpolation function that allows you to intercept the value from the axis label\n labelInterpolationFnc: Chartist.noop,\n // Set the axis type to be used to project values on this axis. If not defined, Chartist.AutoScaleAxis will be used for the Y-Axis, where the high and low options will be set to the global high and low options. This type can be changed to any axis constructor available (e.g. Chartist.FixedScaleAxis), where all axis options should be present here.\n type: undefined,\n // This value specifies the minimum height in pixel of the scale steps\n scaleMinSpace: 20,\n // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false\n },\n // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')\n width: undefined,\n // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')\n height: undefined,\n // If the line should be drawn or not\n showLine: true,\n // If dots should be drawn or not\n showPoint: true,\n // If the line chart should draw an area\n showArea: false,\n // The base for the area chart that will be used to close the area shape (is normally 0)\n areaBase: 0,\n // Specify if the lines should be smoothed. This value can be true or false where true will result in smoothing using the default smoothing interpolation function Chartist.Interpolation.cardinal and false results in Chartist.Interpolation.none. You can also choose other smoothing / interpolation functions available in the Chartist.Interpolation module, or write your own interpolation function. Check the examples for a brief description.\n lineSmooth: true,\n // If the line chart should add a background fill to the .ct-grids group.\n showGridBackground: false,\n // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value\n low: undefined,\n // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value\n high: undefined,\n // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}\n chartPadding: {\n top: 15,\n right: 15,\n bottom: 5,\n left: 10\n },\n // When set to true, the last grid line on the x-axis is not drawn and the chart elements will expand to the full available width of the chart. For the last label to be drawn correctly you might need to add chart padding or offset the last label with a draw event handler.\n fullWidth: false,\n // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.\n reverseData: false,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-line',\n label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n line: 'ct-line',\n point: 'ct-point',\n area: 'ct-area',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n gridBackground: 'ct-grid-background',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal',\n start: 'ct-start',\n end: 'ct-end'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var data = Chartist.normalizeData(this.data, options.reverseData, true);\n\n // Create new svg object\n this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);\n // Create groups for labels, grid and series\n var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n var seriesGroup = this.svg.elem('g');\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n var axisX, axisY;\n\n if(options.axisX.type === undefined) {\n axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {\n ticks: data.normalized.labels,\n stretch: options.fullWidth\n }));\n } else {\n axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {\n high: Chartist.isNumeric(options.high) ? options.high : options.axisY.high,\n low: Chartist.isNumeric(options.low) ? options.low : options.axisY.low\n }));\n } else {\n axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY);\n }\n\n axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);\n axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);\n\n if (options.showGridBackground) {\n Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);\n }\n\n // Draw the series\n data.raw.series.forEach(function(series, seriesIndex) {\n var seriesElement = seriesGroup.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesElement.attr({\n 'ct:series-name': series.name,\n 'ct:meta': Chartist.serialize(series.meta)\n });\n\n // Use series class from series data or if not set generate one\n seriesElement.addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n var pathCoordinates = [],\n pathData = [];\n\n data.normalized.series[seriesIndex].forEach(function(value, valueIndex) {\n var p = {\n x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]),\n y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex])\n };\n pathCoordinates.push(p.x, p.y);\n pathData.push({\n value: value,\n valueIndex: valueIndex,\n meta: Chartist.getMetaData(series, valueIndex)\n });\n }.bind(this));\n\n var seriesOptions = {\n lineSmooth: Chartist.getSeriesOption(series, options, 'lineSmooth'),\n showPoint: Chartist.getSeriesOption(series, options, 'showPoint'),\n showLine: Chartist.getSeriesOption(series, options, 'showLine'),\n showArea: Chartist.getSeriesOption(series, options, 'showArea'),\n areaBase: Chartist.getSeriesOption(series, options, 'areaBase')\n };\n\n var smoothing = typeof seriesOptions.lineSmooth === 'function' ?\n seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.monotoneCubic() : Chartist.Interpolation.none());\n // Interpolating path where pathData will be used to annotate each path element so we can trace back the original\n // index, value and meta data\n var path = smoothing(pathCoordinates, pathData);\n\n // If we should show points we need to create them now to avoid secondary loop\n // Points are drawn from the pathElements returned by the interpolation function\n // Small offset for Firefox to render squares correctly\n if (seriesOptions.showPoint) {\n\n path.pathElements.forEach(function(pathElement) {\n var point = seriesElement.elem('line', {\n x1: pathElement.x,\n y1: pathElement.y,\n x2: pathElement.x + 0.01,\n y2: pathElement.y\n }, options.classNames.point).attr({\n 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNumeric).join(','),\n 'ct:meta': Chartist.serialize(pathElement.data.meta)\n });\n\n this.eventEmitter.emit('draw', {\n type: 'point',\n value: pathElement.data.value,\n index: pathElement.data.valueIndex,\n meta: pathElement.data.meta,\n series: series,\n seriesIndex: seriesIndex,\n axisX: axisX,\n axisY: axisY,\n group: seriesElement,\n element: point,\n x: pathElement.x,\n y: pathElement.y\n });\n }.bind(this));\n }\n\n if(seriesOptions.showLine) {\n var line = seriesElement.elem('path', {\n d: path.stringify()\n }, options.classNames.line, true);\n\n this.eventEmitter.emit('draw', {\n type: 'line',\n values: data.normalized.series[seriesIndex],\n path: path.clone(),\n chartRect: chartRect,\n index: seriesIndex,\n series: series,\n seriesIndex: seriesIndex,\n seriesMeta: series.meta,\n axisX: axisX,\n axisY: axisY,\n group: seriesElement,\n element: line\n });\n }\n\n // Area currently only works with axes that support a range!\n if(seriesOptions.showArea && axisY.range) {\n // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that\n // the area is not drawn outside the chart area.\n var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min);\n\n // We project the areaBase value into screen coordinates\n var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase);\n\n // In order to form the area we'll first split the path by move commands so we can chunk it up into segments\n path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) {\n // We filter only \"solid\" segments that contain more than one point. Otherwise there's no need for an area\n return pathSegment.pathElements.length > 1;\n }).map(function convertToArea(solidPathSegments) {\n // Receiving the filtered solid path segments we can now convert those segments into fill areas\n var firstElement = solidPathSegments.pathElements[0];\n var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1];\n\n // Cloning the solid path segment with closing option and removing the first move command from the clone\n // We then insert a new move that should start at the area base and draw a straight line up or down\n // at the end of the path we add an additional straight line to the projected area base value\n // As the closing option is set our path will be automatically closed\n return solidPathSegments.clone(true)\n .position(0)\n .remove(1)\n .move(firstElement.x, areaBaseProjected)\n .line(firstElement.x, firstElement.y)\n .position(solidPathSegments.pathElements.length + 1)\n .line(lastElement.x, areaBaseProjected);\n\n }).forEach(function createArea(areaPath) {\n // For each of our newly created area paths, we'll now create path elements by stringifying our path objects\n // and adding the created DOM elements to the correct series group\n var area = seriesElement.elem('path', {\n d: areaPath.stringify()\n }, options.classNames.area, true);\n\n // Emit an event for each area that was drawn\n this.eventEmitter.emit('draw', {\n type: 'area',\n values: data.normalized.series[seriesIndex],\n path: areaPath.clone(),\n series: series,\n seriesIndex: seriesIndex,\n axisX: axisX,\n axisY: axisY,\n chartRect: chartRect,\n index: seriesIndex,\n group: seriesElement,\n element: area\n });\n }.bind(this));\n }\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: axisY.bounds,\n chartRect: chartRect,\n axisX: axisX,\n axisY: axisY,\n svg: this.svg,\n options: options\n });\n }\n\n /**\n * This method creates a new line chart.\n *\n * @memberof Chartist.Line\n * @param {String|Node} query A selector query string or directly a DOM element\n * @param {Object} data The data object that needs to consist of a labels and a series array\n * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.\n * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]\n * @return {Object} An object which exposes the API for the created chart\n *\n * @example\n * // Create a simple line chart\n * var data = {\n * // A labels array that can contain any sort of values\n * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],\n * // Our series array that contains series objects or in this case series data arrays\n * series: [\n * [5, 2, 4, 2, 0]\n * ]\n * };\n *\n * // As options we currently only set a static size of 300x200 px\n * var options = {\n * width: '300px',\n * height: '200px'\n * };\n *\n * // In the global name space Chartist we call the Line function to initialize a line chart. As a first parameter we pass in a selector where we would like to get our chart created. Second parameter is the actual data object and as a third parameter we pass in our options\n * new Chartist.Line('.ct-chart', data, options);\n *\n * @example\n * // Use specific interpolation function with configuration from the Chartist.Interpolation module\n *\n * var chart = new Chartist.Line('.ct-chart', {\n * labels: [1, 2, 3, 4, 5],\n * series: [\n * [1, 1, 8, 1, 7]\n * ]\n * }, {\n * lineSmooth: Chartist.Interpolation.cardinal({\n * tension: 0.2\n * })\n * });\n *\n * @example\n * // Create a line chart with responsive options\n *\n * var data = {\n * // A labels array that can contain any sort of values\n * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],\n * // Our series array that contains series objects or in this case series data arrays\n * series: [\n * [5, 2, 4, 2, 0]\n * ]\n * };\n *\n * // In addition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries.\n * var responsiveOptions = [\n * ['screen and (min-width: 641px) and (max-width: 1024px)', {\n * showPoint: false,\n * axisX: {\n * labelInterpolationFnc: function(value) {\n * // Will return Mon, Tue, Wed etc. on medium screens\n * return value.slice(0, 3);\n * }\n * }\n * }],\n * ['screen and (max-width: 640px)', {\n * showLine: false,\n * axisX: {\n * labelInterpolationFnc: function(value) {\n * // Will return M, T, W etc. on small screens\n * return value[0];\n * }\n * }\n * }]\n * ];\n *\n * new Chartist.Line('.ct-chart', data, null, responsiveOptions);\n *\n */\n function Line(query, data, options, responsiveOptions) {\n Chartist.Line.super.constructor.call(this,\n query,\n data,\n defaultOptions,\n Chartist.extend({}, defaultOptions, options),\n responsiveOptions);\n }\n\n // Creating line chart type in Chartist namespace\n Chartist.Line = Chartist.Base.extend({\n constructor: Line,\n createChart: createChart\n });\n\n}(window, document, Chartist));\n;/**\n * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts.\n *\n * @module Chartist.Bar\n */\n/* global Chartist */\n(function(window, document, Chartist){\n 'use strict';\n\n /**\n * Default options in bar charts. Expand the code view to see a detailed list of options with comments.\n *\n * @memberof Chartist.Bar\n */\n var defaultOptions = {\n // Options for X-Axis\n axisX: {\n // The offset of the chart drawing area to the border of the container\n offset: 30,\n // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.\n position: 'end',\n // Allows you to correct label positioning on this axis by positive or negative x and y offset.\n labelOffset: {\n x: 0,\n y: 0\n },\n // If labels should be shown or not\n showLabel: true,\n // If the axis grid should be drawn or not\n showGrid: true,\n // Interpolation function that allows you to intercept the value from the axis label\n labelInterpolationFnc: Chartist.noop,\n // This value specifies the minimum width in pixel of the scale steps\n scaleMinSpace: 30,\n // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false\n },\n // Options for Y-Axis\n axisY: {\n // The offset of the chart drawing area to the border of the container\n offset: 40,\n // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.\n position: 'start',\n // Allows you to correct label positioning on this axis by positive or negative x and y offset.\n labelOffset: {\n x: 0,\n y: 0\n },\n // If labels should be shown or not\n showLabel: true,\n // If the axis grid should be drawn or not\n showGrid: true,\n // Interpolation function that allows you to intercept the value from the axis label\n labelInterpolationFnc: Chartist.noop,\n // This value specifies the minimum height in pixel of the scale steps\n scaleMinSpace: 20,\n // Use only integer values (whole numbers) for the scale steps\n onlyInteger: false\n },\n // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')\n width: undefined,\n // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')\n height: undefined,\n // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value\n high: undefined,\n // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value\n low: undefined,\n // Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale.\n referenceValue: 0,\n // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}\n chartPadding: {\n top: 15,\n right: 15,\n bottom: 5,\n left: 10\n },\n // Specify the distance in pixel of bars in a group\n seriesBarDistance: 15,\n // If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options.\n stackBars: false,\n // If set to 'overlap' this property will force the stacked bars to draw from the zero line.\n // If set to 'accumulate' this property will form a total for each series point. This will also influence the y-axis and the overall bounds of the chart. In stacked mode the seriesBarDistance property will have no effect.\n stackMode: 'accumulate',\n // Inverts the axes of the bar chart in order to draw a horizontal bar chart. Be aware that you also need to invert your axis settings as the Y Axis will now display the labels and the X Axis the values.\n horizontalBars: false,\n // If set to true then each bar will represent a series and the data array is expected to be a one dimensional array of data values rather than a series array of series. This is useful if the bar chart should represent a profile rather than some data over time.\n distributeSeries: false,\n // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.\n reverseData: false,\n // If the bar chart should add a background fill to the .ct-grids group.\n showGridBackground: false,\n // Override the class names that get used to generate the SVG structure of the chart\n classNames: {\n chart: 'ct-chart-bar',\n horizontalBars: 'ct-horizontal-bars',\n label: 'ct-label',\n labelGroup: 'ct-labels',\n series: 'ct-series',\n bar: 'ct-bar',\n grid: 'ct-grid',\n gridGroup: 'ct-grids',\n gridBackground: 'ct-grid-background',\n vertical: 'ct-vertical',\n horizontal: 'ct-horizontal',\n start: 'ct-start',\n end: 'ct-end'\n }\n };\n\n /**\n * Creates a new chart\n *\n */\n function createChart(options) {\n var data;\n var highLow;\n\n if(options.distributeSeries) {\n data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');\n data.normalized.series = data.normalized.series.map(function(value) {\n return [value];\n });\n } else {\n data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');\n }\n\n // Create new svg element\n this.svg = Chartist.createSvg(\n this.container,\n options.width,\n options.height,\n options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '')\n );\n\n // Drawing groups in correct order\n var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);\n var seriesGroup = this.svg.elem('g');\n var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);\n\n if(options.stackBars && data.normalized.series.length !== 0) {\n\n // If stacked bars we need to calculate the high low from stacked values from each series\n var serialSums = Chartist.serialMap(data.normalized.series, function serialSums() {\n return Array.prototype.slice.call(arguments).map(function(value) {\n return value;\n }).reduce(function(prev, curr) {\n return {\n x: prev.x + (curr && curr.x) || 0,\n y: prev.y + (curr && curr.y) || 0\n };\n }, {x: 0, y: 0});\n });\n\n highLow = Chartist.getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y');\n\n } else {\n\n highLow = Chartist.getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y');\n }\n\n // Overrides of high / low from settings\n highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high);\n highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low);\n\n var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n\n var valueAxis,\n labelAxisTicks,\n labelAxis,\n axisX,\n axisY;\n\n // We need to set step count based on some options combinations\n if(options.distributeSeries && options.stackBars) {\n // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should\n // use only the first label for the step axis\n labelAxisTicks = data.normalized.labels.slice(0, 1);\n } else {\n // If distributed series are enabled but stacked bars aren't, we should use the series labels\n // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array\n // as the bars are normalized\n labelAxisTicks = data.normalized.labels;\n }\n\n // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary.\n if(options.horizontalBars) {\n if(options.axisX.type === undefined) {\n valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {\n highLow: highLow,\n referenceValue: 0\n }));\n }\n\n if(options.axisY.type === undefined) {\n labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY);\n }\n } else {\n if(options.axisX.type === undefined) {\n labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, {\n ticks: labelAxisTicks\n });\n } else {\n labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX);\n }\n\n if(options.axisY.type === undefined) {\n valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\n }));\n } else {\n valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {\n highLow: highLow,\n referenceValue: 0\n }));\n }\n }\n\n // Projected 0 point\n var zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0)) : (chartRect.y1 - valueAxis.projectValue(0));\n // Used to track the screen coordinates of stacked bars\n var stackedBarValues = [];\n\n labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);\n valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);\n\n if (options.showGridBackground) {\n Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);\n }\n\n // Draw the series\n data.raw.series.forEach(function(series, seriesIndex) {\n // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc.\n var biPol = seriesIndex - (data.raw.series.length - 1) / 2;\n // Half of the period width between vertical grid lines used to position bars\n var periodHalfLength;\n // Current series SVG element\n var seriesElement;\n\n // We need to set periodHalfLength based on some options combinations\n if(options.distributeSeries && !options.stackBars) {\n // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array\n // which is the series count and divide by 2\n periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2;\n } else if(options.distributeSeries && options.stackBars) {\n // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis\n // length by 2\n periodHalfLength = labelAxis.axisLength / 2;\n } else {\n // On regular bar charts we should just use the series length\n periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2;\n }\n\n // Adding the series group to the series element\n seriesElement = seriesGroup.elem('g');\n\n // Write attributes to series group element. If series name or meta is undefined the attributes will not be written\n seriesElement.attr({\n 'ct:series-name': series.name,\n 'ct:meta': Chartist.serialize(series.meta)\n });\n\n // Use series class from series data or if not set generate one\n seriesElement.addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))\n ].join(' '));\n\n data.normalized.series[seriesIndex].forEach(function(value, valueIndex) {\n var projected,\n bar,\n previousStack,\n labelAxisValueIndex;\n\n // We need to set labelAxisValueIndex based on some options combinations\n if(options.distributeSeries && !options.stackBars) {\n // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection\n // on the step axis for label positioning\n labelAxisValueIndex = seriesIndex;\n } else if(options.distributeSeries && options.stackBars) {\n // If distributed series and stacked bars are enabled, we will only get one bar and therefore always use\n // 0 for projection on the label step axis\n labelAxisValueIndex = 0;\n } else {\n // On regular bar charts we just use the value index to project on the label step axis\n labelAxisValueIndex = valueIndex;\n }\n\n // We need to transform coordinates differently based on the chart layout\n if(options.horizontalBars) {\n projected = {\n x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]),\n y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex])\n };\n } else {\n projected = {\n x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]),\n y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex])\n }\n }\n\n // If the label axis is a step based axis we will offset the bar into the middle of between two steps using\n // the periodHalfLength value. Also we do arrange the different series so that they align up to each other using\n // the seriesBarDistance. If we don't have a step axis, the bar positions can be chosen freely so we should not\n // add any automated positioning.\n if(labelAxis instanceof Chartist.StepAxis) {\n // Offset to center bar between grid lines, but only if the step axis is not stretched\n if(!labelAxis.options.stretch) {\n projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);\n }\n // Using bi-polar offset for multiple series if no stacked bars or series distribution is used\n projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);\n }\n\n // Enter value in stacked bar values used to remember previous screen value for stacking up bars\n previousStack = stackedBarValues[valueIndex] || zeroPoint;\n stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]);\n\n // Skip if value is undefined\n if(value === undefined) {\n return;\n }\n\n var positions = {};\n positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];\n positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];\n\n if(options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) {\n // Stack mode: accumulate (default)\n // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line\n // We want backwards compatibility, so the expected fallback without the 'stackMode' option\n // to be the original behaviour (accumulate)\n positions[labelAxis.counterUnits.pos + '1'] = previousStack;\n positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex];\n } else {\n // Draw from the zero line normally\n // This is also the same code for Stack mode: overlap\n positions[labelAxis.counterUnits.pos + '1'] = zeroPoint;\n positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos];\n }\n\n // Limit x and y so that they are within the chart rect\n positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2);\n positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2);\n positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1);\n positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1);\n\n var metaData = Chartist.getMetaData(series, valueIndex);\n\n // Create bar element\n bar = seriesElement.elem('line', positions, options.classNames.bar).attr({\n 'ct:value': [value.x, value.y].filter(Chartist.isNumeric).join(','),\n 'ct:meta': Chartist.serialize(metaData)\n });\n\n this.eventEmitter.emit('draw', Chartist.extend({\n type: 'bar',\n value: value,\n index: valueIndex,\n meta: metaData,\n series: series,\n seriesIndex: seriesIndex,\n axisX: axisX,\n axisY: axisY,\n chartRect: chartRect,\n group: seriesElement,\n element: bar\n }, positions));\n }.bind(this));\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n bounds: valueAxis.bounds,\n chartRect: chartRect,\n axisX: axisX,\n axisY: axisY,\n svg: this.svg,\n options: options\n });\n }\n\n /**\n * This method creates a new bar chart and returns API object that you can use for later changes.\n *\n * @memberof Chartist.Bar\n * @param {String|Node} query A selector query string or directly a DOM element\n * @param {Object} data The data object that needs to consist of a labels and a series array\n * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.\n * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]\n * @return {Object} An object which exposes the API for the created chart\n *\n * @example\n * // Create a simple bar chart\n * var data = {\n * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],\n * series: [\n * [5, 2, 4, 2, 0]\n * ]\n * };\n *\n * // In the global name space Chartist we call the Bar function to initialize a bar chart. As a first parameter we pass in a selector where we would like to get our chart created and as a second parameter we pass our data object.\n * new Chartist.Bar('.ct-chart', data);\n *\n * @example\n * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10\n * new Chartist.Bar('.ct-chart', {\n * labels: [1, 2, 3, 4, 5, 6, 7],\n * series: [\n * [1, 3, 2, -5, -3, 1, -6],\n * [-5, -2, -4, -1, 2, -3, 1]\n * ]\n * }, {\n * seriesBarDistance: 12,\n * low: -10,\n * high: 10\n * });\n *\n */\n function Bar(query, data, options, responsiveOptions) {\n Chartist.Bar.super.constructor.call(this,\n query,\n data,\n defaultOptions,\n Chartist.extend({}, defaultOptions, options),\n responsiveOptions);\n }\n\n // Creating bar chart type in Chartist namespace\n Chartist.Bar = Chartist.Base.extend({\n constructor: Bar,\n createChart: createChart\n });\n\n}(window, document, Chartist));\n;/**\n * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts\n *\n * @module Chartist.Pie\n */\n/* global Chartist */\n(function(window, document, Chartist) {\n 'use strict';\n\n /**\n * Default options in line charts. Expand the code view to see a detailed list of options with comments.\n *\n * @memberof Chartist.Pie\n */\n var defaultOptions = {\n // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')\n width: undefined,\n // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')\n height: undefined,\n // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}\n chartPadding: 5,\n // Override the class names that are used to generate the SVG structure of the chart\n classNames: {\n chartPie: 'ct-chart-pie',\n chartDonut: 'ct-chart-donut',\n series: 'ct-series',\n slicePie: 'ct-slice-pie',\n sliceDonut: 'ct-slice-donut',\n sliceDonutSolid: 'ct-slice-donut-solid',\n label: 'ct-label'\n },\n // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise.\n startAngle: 0,\n // An optional total you can specify. By specifying a total value, the sum of the values in the series must be this total in order to draw a full pie. You can use this parameter to draw only parts of a pie or gauge charts.\n total: undefined,\n // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices.\n donut: false,\n // If specified the donut segments will be drawn as shapes instead of strokes.\n donutSolid: false,\n // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future.\n // This option can be set as number or string to specify a relative width (i.e. 100 or '30%').\n donutWidth: 60,\n // If a label should be shown or not\n showLabel: true,\n // Label position offset from the standard position which is half distance of the radius. This value can be either positive or negative. Positive values will position the label away from the center.\n labelOffset: 0,\n // This option can be set to 'inside', 'outside' or 'center'. Positioned with 'inside' the labels will be placed on half the distance of the radius to the border of the Pie by respecting the 'labelOffset'. The 'outside' option will place the labels at the border of the pie and 'center' will place the labels in the absolute center point of the chart. The 'center' option only makes sense in conjunction with the 'labelOffset' option.\n labelPosition: 'inside',\n // An interpolation function for the label value\n labelInterpolationFnc: Chartist.noop,\n // Label direction can be 'neutral', 'explode' or 'implode'. The labels anchor will be positioned based on those settings as well as the fact if the labels are on the right or left side of the center of the chart. Usually explode is useful when labels are positioned far away from the center.\n labelDirection: 'neutral',\n // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.\n reverseData: false,\n // If true empty values will be ignored to avoid drawing unncessary slices and labels\n ignoreEmptyValues: false\n };\n\n /**\n * Determines SVG anchor position based on direction and center parameter\n *\n * @param center\n * @param label\n * @param direction\n * @return {string}\n */\n function determineAnchorPosition(center, label, direction) {\n var toTheRight = label.x > center.x;\n\n if(toTheRight && direction === 'explode' ||\n !toTheRight && direction === 'implode') {\n return 'start';\n } else if(toTheRight && direction === 'implode' ||\n !toTheRight && direction === 'explode') {\n return 'end';\n } else {\n return 'middle';\n }\n }\n\n /**\n * Creates the pie chart\n *\n * @param options\n */\n function createChart(options) {\n var data = Chartist.normalizeData(this.data);\n var seriesGroups = [],\n labelsGroup,\n chartRect,\n radius,\n labelRadius,\n totalDataSum,\n startAngle = options.startAngle;\n\n // Create SVG.js draw\n this.svg = Chartist.createSvg(this.container, options.width, options.height,options.donut ? options.classNames.chartDonut : options.classNames.chartPie);\n // Calculate charting rect\n chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);\n // Get biggest circle radius possible within chartRect\n radius = Math.min(chartRect.width() / 2, chartRect.height() / 2);\n // Calculate total of all series to get reference value or use total reference from optional options\n totalDataSum = options.total || data.normalized.series.reduce(function(previousValue, currentValue) {\n return previousValue + currentValue;\n }, 0);\n\n var donutWidth = Chartist.quantity(options.donutWidth);\n if (donutWidth.unit === '%') {\n donutWidth.value *= radius / 100;\n }\n\n // If this is a donut chart we need to adjust our radius to enable strokes to be drawn inside\n // Unfortunately this is not possible with the current SVG Spec\n // See this proposal for more details: http://lists.w3.org/Archives/Public/www-svg/2003Oct/0000.html\n radius -= options.donut && !options.donutSolid ? donutWidth.value / 2 : 0;\n\n // If labelPosition is set to `outside` or a donut chart is drawn then the label position is at the radius,\n // if regular pie chart it's half of the radius\n if(options.labelPosition === 'outside' || options.donut && !options.donutSolid) {\n labelRadius = radius;\n } else if(options.labelPosition === 'center') {\n // If labelPosition is center we start with 0 and will later wait for the labelOffset\n labelRadius = 0;\n } else if(options.donutSolid) {\n labelRadius = radius - donutWidth.value / 2;\n } else {\n // Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie\n // slice\n labelRadius = radius / 2;\n }\n // Add the offset to the labelRadius where a negative offset means closed to the center of the chart\n labelRadius += options.labelOffset;\n\n // Calculate end angle based on total sum and current data value and offset with padding\n var center = {\n x: chartRect.x1 + chartRect.width() / 2,\n y: chartRect.y2 + chartRect.height() / 2\n };\n\n // Check if there is only one non-zero value in the series array.\n var hasSingleValInSeries = data.raw.series.filter(function(val) {\n return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;\n }).length === 1;\n\n // Creating the series groups\n data.raw.series.forEach(function(series, index) {\n seriesGroups[index] = this.svg.elem('g', null, null);\n }.bind(this));\n //if we need to show labels we create the label group now\n if(options.showLabel) {\n labelsGroup = this.svg.elem('g', null, null);\n }\n\n // Draw the series\n // initialize series groups\n data.raw.series.forEach(function(series, index) {\n // If current value is zero and we are ignoring empty values then skip to next value\n if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return;\n\n // If the series is an object and contains a name or meta data we add a custom attribute\n seriesGroups[index].attr({\n 'ct:series-name': series.name\n });\n\n // Use series class from series data or if not set generate one\n seriesGroups[index].addClass([\n options.classNames.series,\n (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(index))\n ].join(' '));\n\n // If the whole dataset is 0 endAngle should be zero. Can't divide by 0.\n var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0);\n\n // Use slight offset so there are no transparent hairline issues\n var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2));\n\n // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle\n // with Z and use 359.99 degrees\n if(endAngle - overlappigStartAngle >= 359.99) {\n endAngle = overlappigStartAngle + 359.99;\n }\n\n var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle),\n end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle);\n\n var innerStart,\n innerEnd,\n donutSolidRadius;\n\n // Create a new path element for the pie chart. If this isn't a donut chart we should close the path for a correct stroke\n var path = new Chartist.Svg.Path(!options.donut || options.donutSolid)\n .move(end.x, end.y)\n .arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y);\n\n // If regular pie chart (no donut) we add a line to the center of the circle for completing the pie\n if(!options.donut) {\n path.line(center.x, center.y);\n } else if (options.donutSolid) {\n donutSolidRadius = radius - donutWidth.value;\n innerStart = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2));\n innerEnd = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, endAngle);\n path.line(innerStart.x, innerStart.y);\n path.arc(donutSolidRadius, donutSolidRadius, 0, endAngle - startAngle > 180, 1, innerEnd.x, innerEnd.y);\n }\n\n // Create the SVG path\n // If this is a donut chart we add the donut class, otherwise just a regular slice\n var pathClassName = options.classNames.slicePie;\n if (options.donut) {\n pathClassName = options.classNames.sliceDonut;\n if (options.donutSolid) {\n pathClassName = options.classNames.sliceDonutSolid;\n }\n }\n var pathElement = seriesGroups[index].elem('path', {\n d: path.stringify()\n }, pathClassName);\n\n // Adding the pie series value to the path\n pathElement.attr({\n 'ct:value': data.normalized.series[index],\n 'ct:meta': Chartist.serialize(series.meta)\n });\n\n // If this is a donut, we add the stroke-width as style attribute\n if(options.donut && !options.donutSolid) {\n pathElement._node.style.strokeWidth = donutWidth.value + 'px';\n }\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'slice',\n value: data.normalized.series[index],\n totalDataSum: totalDataSum,\n index: index,\n meta: series.meta,\n series: series,\n group: seriesGroups[index],\n element: pathElement,\n path: path.clone(),\n center: center,\n radius: radius,\n startAngle: startAngle,\n endAngle: endAngle\n });\n\n // If we need to show labels we need to add the label for this slice now\n if(options.showLabel) {\n var labelPosition;\n if(data.raw.series.length === 1) {\n // If we have only 1 series, we can position the label in the center of the pie\n labelPosition = {\n x: center.x,\n y: center.y\n };\n } else {\n // Position at the labelRadius distance from center and between start and end angle\n labelPosition = Chartist.polarToCartesian(\n center.x,\n center.y,\n labelRadius,\n startAngle + (endAngle - startAngle) / 2\n );\n }\n\n var rawValue;\n if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[index])) {\n rawValue = data.normalized.labels[index];\n } else {\n rawValue = data.normalized.series[index];\n }\n\n var interpolatedValue = options.labelInterpolationFnc(rawValue, index);\n\n if(interpolatedValue || interpolatedValue === 0) {\n var labelElement = labelsGroup.elem('text', {\n dx: labelPosition.x,\n dy: labelPosition.y,\n 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection)\n }, options.classNames.label).text('' + interpolatedValue);\n\n // Fire off draw event\n this.eventEmitter.emit('draw', {\n type: 'label',\n index: index,\n group: labelsGroup,\n element: labelElement,\n text: '' + interpolatedValue,\n x: labelPosition.x,\n y: labelPosition.y\n });\n }\n }\n\n // Set next startAngle to current endAngle.\n // (except for last slice)\n startAngle = endAngle;\n }.bind(this));\n\n this.eventEmitter.emit('created', {\n chartRect: chartRect,\n svg: this.svg,\n options: options\n });\n }\n\n /**\n * This method creates a new pie chart and returns an object that can be used to redraw the chart.\n *\n * @memberof Chartist.Pie\n * @param {String|Node} query A selector query string or directly a DOM element\n * @param {Object} data The data object in the pie chart needs to have a series property with a one dimensional data array. The values will be normalized against each other and don't necessarily need to be in percentage. The series property can also be an array of value objects that contain a value property and a className property to override the CSS class name for the series group.\n * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.\n * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]\n * @return {Object} An object with a version and an update method to manually redraw the chart\n *\n * @example\n * // Simple pie chart example with four series\n * new Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * });\n *\n * @example\n * // Drawing a donut chart\n * new Chartist.Pie('.ct-chart', {\n * series: [10, 2, 4, 3]\n * }, {\n * donut: true\n * });\n *\n * @example\n * // Using donut, startAngle and total to draw a gauge chart\n * new Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * donut: true,\n * donutWidth: 20,\n * startAngle: 270,\n * total: 200\n * });\n *\n * @example\n * // Drawing a pie chart with padding and labels that are outside the pie\n * new Chartist.Pie('.ct-chart', {\n * series: [20, 10, 30, 40]\n * }, {\n * chartPadding: 30,\n * labelOffset: 50,\n * labelDirection: 'explode'\n * });\n *\n * @example\n * // Overriding the class names for individual series as well as a name and meta data.\n * // The name will be written as ct:series-name attribute and the meta data will be serialized and written\n * // to a ct:meta attribute.\n * new Chartist.Pie('.ct-chart', {\n * series: [{\n * value: 20,\n * name: 'Series 1',\n * className: 'my-custom-class-one',\n * meta: 'Meta One'\n * }, {\n * value: 10,\n * name: 'Series 2',\n * className: 'my-custom-class-two',\n * meta: 'Meta Two'\n * }, {\n * value: 70,\n * name: 'Series 3',\n * className: 'my-custom-class-three',\n * meta: 'Meta Three'\n * }]\n * });\n */\n function Pie(query, data, options, responsiveOptions) {\n Chartist.Pie.super.constructor.call(this,\n query,\n data,\n defaultOptions,\n Chartist.extend({}, defaultOptions, options),\n responsiveOptions);\n }\n\n // Creating pie chart type in Chartist namespace\n Chartist.Pie = Chartist.Base.extend({\n constructor: Pie,\n createChart: createChart,\n determineAnchorPosition: determineAnchorPosition\n });\n\n}(window, document, Chartist));\n\nreturn Chartist;\n\n}));\n"]}
\ No newline at end of file
diff --git a/contao/assets/chartist/dist/scss/chartist.scss b/contao/assets/chartist/dist/scss/chartist.scss
index e3caaa6..e5c6b42 100644
--- a/contao/assets/chartist/dist/scss/chartist.scss
+++ b/contao/assets/chartist/dist/scss/chartist.scss
@@ -107,7 +107,7 @@
stroke: $color;
}
- .#{$ct-class-slice-pie}, .#{$ct-class-area} {
+ .#{$ct-class-slice-pie}, .#{$ct-class-slice-donut-solid}, .#{$ct-class-area} {
fill: $color;
}
}
diff --git a/contao/assets/chartist/dist/scss/settings/_chartist-settings.scss b/contao/assets/chartist/dist/scss/settings/_chartist-settings.scss
index 4d0370e..def297c 100644
--- a/contao/assets/chartist/dist/scss/settings/_chartist-settings.scss
+++ b/contao/assets/chartist/dist/scss/settings/_chartist-settings.scss
@@ -17,6 +17,7 @@ $ct-class-area: ct-area !default;
$ct-class-bar: ct-bar !default;
$ct-class-slice-pie: ct-slice-pie !default;
$ct-class-slice-donut: ct-slice-donut !default;
+$ct-class-slice-donut-solid: ct-slice-donut-solid !default;
$ct-class-grid: ct-grid !default;
$ct-class-grid-background: ct-grid-background !default;
$ct-class-vertical: ct-vertical !default;
diff --git a/contao/assets/chartjs/.codeclimate.yml b/contao/assets/chartjs/.codeclimate.yml
deleted file mode 100644
index ee3a5fd..0000000
--- a/contao/assets/chartjs/.codeclimate.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-engines:
- duplication:
- enabled: true
- config:
- languages:
- - javascript
- eslint:
- enabled: true
- channel: "eslint-3"
- fixme:
- enabled: true
-ratings:
- paths:
- - "src/**/*.js"
-exclude_paths:
-- dist/**/*
-- node_modules/**/*
-- test/**/*
-- coverage/**/*
diff --git a/contao/assets/chartjs/.github/ISSUE_TEMPLATE.md b/contao/assets/chartjs/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 7d57bbd..0000000
--- a/contao/assets/chartjs/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-## Expected Behavior
-
-
-
-## Current Behavior
-
-
-
-## Possible Solution
-
-
-
-## Steps to Reproduce (for bugs)
-
-
-1.
-2.
-3.
-4.
-
-## Context
-
-
-
-## Environment
-
-* Chart.js version:
-* Browser name and version:
-* Link to your project:
diff --git a/contao/assets/chartjs/.github/PULL_REQUEST_TEMPLATE.md b/contao/assets/chartjs/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index b57d497..0000000
--- a/contao/assets/chartjs/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,9 +0,0 @@
-Please consider the following before submitting a pull request:
-
-Guidelines for contributing: https://github.com/chartjs/Chart.js/blob/master/CONTRIBUTING.md
-
-Example of changes on an interactive website such as the following:
-- http://jsbin.com/
-- http://jsfiddle.net/
-- http://codepen.io/pen/
-- Premade template: http://codepen.io/pen?template=JXVYzq
\ No newline at end of file
diff --git a/contao/assets/chartjs/.gitignore b/contao/assets/chartjs/.gitignore
deleted file mode 100644
index 8ef0139..0000000
--- a/contao/assets/chartjs/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-/coverage
-/custom
-/dist
-/docs/index.md
-/node_modules
-
-.DS_Store
-.idea
-.vscode
-bower.json
diff --git a/contao/assets/chartjs/.npmignore b/contao/assets/chartjs/.npmignore
deleted file mode 100644
index 47b4948..0000000
--- a/contao/assets/chartjs/.npmignore
+++ /dev/null
@@ -1,13 +0,0 @@
-/.git
-/.github
-/coverage
-/custom
-/dist/*.zip
-/docs/index.md
-/node_modules
-
-.codeclimate.yml
-.DS_Store
-.gitignore
-.idea
-.travis.yml
diff --git a/contao/assets/chartjs/.travis.yml b/contao/assets/chartjs/.travis.yml
deleted file mode 100644
index 2df4a4c..0000000
--- a/contao/assets/chartjs/.travis.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-language: node_js
-node_js:
- - "5.10"
-
-before_install:
- - "export CHROME_BIN=/usr/bin/google-chrome"
- - "export DISPLAY=:99.0"
- - "sh -e /etc/init.d/xvfb start"
-
-before_script:
- - npm install
-
-script:
- - gulp build
- - gulp test
- - gulp coverage
- - gulp package
- - gulp bower
- - cat ./coverage/lcov.info | ./node_modules/.bin/coveralls
-
-notifications:
- slack: chartjs:pcfCZR6ugg5TEcaLtmIfQYuA
-
-sudo: required
-dist: trusty
-
-addons:
- firefox: latest
- apt:
- sources:
- - google-chrome
- packages:
- - google-chrome-stable
-
-deploy:
-# Creates a tag containing dist files and bower.json
-# Requires GITHUB_AUTH_TOKEN and GITHUB_AUTH_EMAIL environment variables
-# IMPORTANT: the script has to be set executable in the Git repository (error 127)
-# https://github.com/travis-ci/travis-ci/issues/5538#issuecomment-225025939
-- provider: script
- script: ./scripts/release.sh
- skip_cleanup: true
- on:
- branch: release
-- provider: releases
- api_key: $GITHUB_AUTH_TOKEN
- file:
- - "./dist/Chart.bundle.js"
- - "./dist/Chart.bundle.min.js"
- - "./dist/Chart.js"
- - "./dist/Chart.min.js"
- - "./dist/Chart.js.zip"
- skip_cleanup: true
- on:
- tags: true
-- provider: npm
- email: $NPM_AUTH_EMAIL
- api_key: $NPM_AUTH_TOKEN
- skip_cleanup: true
- on:
- tags: true
diff --git a/contao/assets/chartjs/CONTRIBUTING.md b/contao/assets/chartjs/CONTRIBUTING.md
deleted file mode 100644
index 6ec1024..0000000
--- a/contao/assets/chartjs/CONTRIBUTING.md
+++ /dev/null
@@ -1,64 +0,0 @@
-Contributing to Chart.js
-========================
-
-Contributions to Chart.js are welcome and encouraged, but please have a look through the guidelines in this document before raising an issue, or writing code for the project.
-
-
-Using issues
-------------
-
-The [issue tracker](https://github.com/chartjs/Chart.js/issues) is the preferred channel for reporting bugs, requesting new features and submitting pull requests.
-
-If you're suggesting a new chart type, please take a look at [writing new chart types](https://github.com/chartjs/Chart.js/blob/master/docs/09-Advanced.md#writing-new-chart-types) in the documentation or consider [creating a plugin](https://github.com/chartjs/Chart.js/blob/master/docs/09-Advanced.md#creating-plugins).
-
-To keep the library lightweight for everyone, it's unlikely we'll add many more chart types to the core of Chart.js, but issues are a good medium to design and spec out how new chart types could work and look.
-
-Please do not use issues for support requests. For help using Chart.js, please take a look at the [`chartjs`](http://stackoverflow.com/questions/tagged/chartjs) tag on Stack Overflow.
-
-
-Reporting bugs
---------------
-
-Well structured, detailed bug reports are hugely valuable for the project.
-
-Guidelines for reporting bugs:
-
- - Check the issue search to see if it has already been reported
- - Isolate the problem to a simple test case
- - Please include a demonstration of the bug on a website such as [JS Bin](http://jsbin.com/), [JS Fiddle](http://jsfiddle.net/), or [Codepen](http://codepen.io/pen/). ([Template](http://codepen.io/pen?template=JXVYzq))
-
-Please provide any additional details associated with the bug, if it's browser or screen density specific, or only happens with a certain configuration or data.
-
-
-Local development
------------------
-
-Run `npm install` to install all the libraries, then run `gulp dev --test` to build and run tests as you make changes.
-
-
-Pull requests
--------------
-
-Clear, concise pull requests are excellent at continuing the project's community driven growth. But please review [these guidelines](https://github.com/blog/1943-how-to-write-the-perfect-pull-request) and the guidelines below before starting work on the project.
-
-Be advised that **Chart.js 1.0.2 is in feature-complete status**. Pull requests adding new features to the 1.x branch will be disregarded.
-
-Guidelines:
-
- - Please create an issue first and/or talk with a team member:
- - For bugs, we can discuss the fixing approach
- - For enhancements, we can discuss if it is within the project scope and avoid duplicate effort
- - Please make changes to the files in [`/src`](https://github.com/chartjs/Chart.js/tree/master/src), not `Chart.js` or `Chart.min.js` in the repo root directory, this avoids merge conflicts
- - Tabs for indentation, not spaces please
- - If adding new functionality, please also update the relevant `.md` file in [`/docs`](https://github.com/chartjs/Chart.js/tree/master/docs)
- - Please make your commits in logical sections with clear commit messages
-
-Joining the project
--------------
- - Active committers and contributors are invited to introduce yourself and request commit access to this project. Please send an email to hello@nickdownie.com or file an issue.
- - We have a very active Slack community that you can join [here](https://chart-js-automation.herokuapp.com/). If you think you can help, we'd love to have you!
-
-License
--------
-
-By contributing your code, you agree to license your contribution under the [MIT license](https://github.com/chartjs/Chart.js/blob/master/LICENSE.md).
diff --git a/contao/assets/chartjs/LICENSE.md b/contao/assets/chartjs/LICENSE.md
index dc93bcc..620db30 100644
--- a/contao/assets/chartjs/LICENSE.md
+++ b/contao/assets/chartjs/LICENSE.md
@@ -1,5 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2013-2016 Nick Downie
+
+Copyright (c) 2013-2017 Nick Downie
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
diff --git a/contao/assets/chartjs/README.md b/contao/assets/chartjs/README.md
index daec17a..d2ed996 100644
--- a/contao/assets/chartjs/README.md
+++ b/contao/assets/chartjs/README.md
@@ -33,21 +33,14 @@ You can find documentation at [www.chartjs.org/docs](http://www.chartjs.org/docs
## Contributing
-Before submitting an issue or a pull request to the project, please take a moment to look over the [contributing guidelines](https://github.com/chartjs/Chart.js/blob/master/CONTRIBUTING.md) first.
+Before submitting an issue or a pull request, please take a moment to look over the [contributing guidelines](https://github.com/chartjs/Chart.js/blob/master/docs/developers/contributing.md) first. For support using Chart.js, please post questions with the [`chartjs` tag on Stack Overflow](http://stackoverflow.com/questions/tagged/chartjs).
-For support using Chart.js, please post questions with the [`chartjs` tag on Stack Overflow](http://stackoverflow.com/questions/tagged/chartjs).
+## Building
+Instructions on building and testing Chart.js can be found in [the documentation](https://github.com/chartjs/Chart.js/blob/master/docs/developers/contributing.md#building-and-testing).
-## Building and Testing
-
-To build, run `gulp build`.
-
-To test, run `gulp test`.
-
-To test against code standards, run `gulp lint`.
-
-More information on building and testing can be found in [gulpfile.js](gulpfile.js).
-
-Thanks to [BrowserStack](https://browserstack.com) for allowing our team to test on thousands of browsers.
+## Thanks
+- [BrowserStack](https://browserstack.com) for allowing our team to test on thousands of browsers.
+- [@n8agrin](https://twitter.com/n8agrin) for the Twitter handle donation.
## License
diff --git a/contao/assets/chartjs/book.json b/contao/assets/chartjs/book.json
new file mode 100644
index 0000000..487fd09
--- /dev/null
+++ b/contao/assets/chartjs/book.json
@@ -0,0 +1,23 @@
+{
+ "root": "./docs",
+ "author": "chartjs",
+ "gitbook": "3.2.2",
+ "plugins": ["-lunr", "-search", "search-plus", "anchorjs", "chartjs", "ga"],
+ "pluginsConfig": {
+ "anchorjs": {
+ "icon": "#",
+ "placement": "left",
+ "visible": "always"
+ },
+ "ga": {
+ "token": "UA-28909194-3",
+ "configuration": "auto"
+ },
+ "theme-default": {
+ "showLevel": false,
+ "styles": {
+ "website": "style.css"
+ }
+ }
+ }
+}
diff --git a/contao/assets/chartjs/config.jshintrc b/contao/assets/chartjs/config.jshintrc
deleted file mode 100644
index 00b4202..0000000
--- a/contao/assets/chartjs/config.jshintrc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "node": true,
- "unused": true,
- "predef": [ "require", "module" ]
-}
\ No newline at end of file
diff --git a/contao/assets/chartjs/dist/Chart.bundle.js b/contao/assets/chartjs/dist/Chart.bundle.js
new file mode 100644
index 0000000..7f5cc01
--- /dev/null
+++ b/contao/assets/chartjs/dist/Chart.bundle.js
@@ -0,0 +1,17220 @@
+/*!
+ * Chart.js
+ * http://chartjs.org/
+ * Version: 2.6.0
+ *
+ * Copyright 2017 Nick Downie
+ * Released under the MIT license
+ * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
+ */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o lum2) {
+ return (lum1 + 0.05) / (lum2 + 0.05);
+ }
+ return (lum2 + 0.05) / (lum1 + 0.05);
+ },
+
+ level: function (color2) {
+ var contrastRatio = this.contrast(color2);
+ if (contrastRatio >= 7.1) {
+ return 'AAA';
+ }
+
+ return (contrastRatio >= 4.5) ? 'AA' : '';
+ },
+
+ dark: function () {
+ // YIQ equation from http://24ways.org/2010/calculating-color-contrast
+ var rgb = this.values.rgb;
+ var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
+ return yiq < 128;
+ },
+
+ light: function () {
+ return !this.dark();
+ },
+
+ negate: function () {
+ var rgb = [];
+ for (var i = 0; i < 3; i++) {
+ rgb[i] = 255 - this.values.rgb[i];
+ }
+ this.setValues('rgb', rgb);
+ return this;
+ },
+
+ lighten: function (ratio) {
+ var hsl = this.values.hsl;
+ hsl[2] += hsl[2] * ratio;
+ this.setValues('hsl', hsl);
+ return this;
+ },
+
+ darken: function (ratio) {
+ var hsl = this.values.hsl;
+ hsl[2] -= hsl[2] * ratio;
+ this.setValues('hsl', hsl);
+ return this;
+ },
+
+ saturate: function (ratio) {
+ var hsl = this.values.hsl;
+ hsl[1] += hsl[1] * ratio;
+ this.setValues('hsl', hsl);
+ return this;
+ },
+
+ desaturate: function (ratio) {
+ var hsl = this.values.hsl;
+ hsl[1] -= hsl[1] * ratio;
+ this.setValues('hsl', hsl);
+ return this;
+ },
+
+ whiten: function (ratio) {
+ var hwb = this.values.hwb;
+ hwb[1] += hwb[1] * ratio;
+ this.setValues('hwb', hwb);
+ return this;
+ },
+
+ blacken: function (ratio) {
+ var hwb = this.values.hwb;
+ hwb[2] += hwb[2] * ratio;
+ this.setValues('hwb', hwb);
+ return this;
+ },
+
+ greyscale: function () {
+ var rgb = this.values.rgb;
+ // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
+ var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
+ this.setValues('rgb', [val, val, val]);
+ return this;
+ },
+
+ clearer: function (ratio) {
+ var alpha = this.values.alpha;
+ this.setValues('alpha', alpha - (alpha * ratio));
+ return this;
+ },
+
+ opaquer: function (ratio) {
+ var alpha = this.values.alpha;
+ this.setValues('alpha', alpha + (alpha * ratio));
+ return this;
+ },
+
+ rotate: function (degrees) {
+ var hsl = this.values.hsl;
+ var hue = (hsl[0] + degrees) % 360;
+ hsl[0] = hue < 0 ? 360 + hue : hue;
+ this.setValues('hsl', hsl);
+ return this;
+ },
+
+ /**
+ * Ported from sass implementation in C
+ * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
+ */
+ mix: function (mixinColor, weight) {
+ var color1 = this;
+ var color2 = mixinColor;
+ var p = weight === undefined ? 0.5 : weight;
+
+ var w = 2 * p - 1;
+ var a = color1.alpha() - color2.alpha();
+
+ var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
+ var w2 = 1 - w1;
+
+ return this
+ .rgb(
+ w1 * color1.red() + w2 * color2.red(),
+ w1 * color1.green() + w2 * color2.green(),
+ w1 * color1.blue() + w2 * color2.blue()
+ )
+ .alpha(color1.alpha() * p + color2.alpha() * (1 - p));
+ },
+
+ toJSON: function () {
+ return this.rgb();
+ },
+
+ clone: function () {
+ // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
+ // making the final build way to big to embed in Chart.js. So let's do it manually,
+ // assuming that values to clone are 1 dimension arrays containing only numbers,
+ // except 'alpha' which is a number.
+ var result = new Color();
+ var source = this.values;
+ var target = result.values;
+ var value, type;
+
+ for (var prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ value = source[prop];
+ type = ({}).toString.call(value);
+ if (type === '[object Array]') {
+ target[prop] = value.slice(0);
+ } else if (type === '[object Number]') {
+ target[prop] = value;
+ } else {
+ console.error('unexpected color value:', value);
+ }
+ }
+ }
+
+ return result;
+ }
+};
+
+Color.prototype.spaces = {
+ rgb: ['red', 'green', 'blue'],
+ hsl: ['hue', 'saturation', 'lightness'],
+ hsv: ['hue', 'saturation', 'value'],
+ hwb: ['hue', 'whiteness', 'blackness'],
+ cmyk: ['cyan', 'magenta', 'yellow', 'black']
+};
+
+Color.prototype.maxes = {
+ rgb: [255, 255, 255],
+ hsl: [360, 100, 100],
+ hsv: [360, 100, 100],
+ hwb: [360, 100, 100],
+ cmyk: [100, 100, 100, 100]
+};
+
+Color.prototype.getValues = function (space) {
+ var values = this.values;
+ var vals = {};
+
+ for (var i = 0; i < space.length; i++) {
+ vals[space.charAt(i)] = values[space][i];
+ }
+
+ if (values.alpha !== 1) {
+ vals.a = values.alpha;
+ }
+
+ // {r: 255, g: 255, b: 255, a: 0.4}
+ return vals;
+};
+
+Color.prototype.setValues = function (space, vals) {
+ var values = this.values;
+ var spaces = this.spaces;
+ var maxes = this.maxes;
+ var alpha = 1;
+ var i;
+
+ this.valid = true;
+
+ 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;
+
+},{"1":1,"4":4}],3:[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;
+}
+
+},{}],4:[function(require,module,exports){
+var conversions = require(3);
+
+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;
+},{"3":3}],5:[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]
+};
+},{}],6:[function(require,module,exports){
+//! moment.js
+//! version : 2.18.1
+//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+//! license : MIT
+//! momentjs.com
+
+;(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ global.moment = factory()
+}(this, (function () { 'use strict';
+
+var hookCallback;
+
+function hooks () {
+ return hookCallback.apply(null, arguments);
+}
+
+// This is done to register the method called with moment()
+// without creating circular dependencies.
+function setHookCallback (callback) {
+ hookCallback = callback;
+}
+
+function isArray(input) {
+ return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
+}
+
+function isObject(input) {
+ // IE8 will treat undefined and null as object if it wasn't for
+ // input != null
+ return input != null && Object.prototype.toString.call(input) === '[object Object]';
+}
+
+function isObjectEmpty(obj) {
+ var k;
+ for (k in obj) {
+ // even if its not own property I'd still call it non-empty
+ return false;
+ }
+ return true;
+}
+
+function isUndefined(input) {
+ return input === void 0;
+}
+
+function isNumber(input) {
+ return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
+}
+
+function isDate(input) {
+ return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
+}
+
+function map(arr, fn) {
+ var res = [], i;
+ for (i = 0; i < arr.length; ++i) {
+ res.push(fn(arr[i], i));
+ }
+ return res;
+}
+
+function hasOwnProp(a, b) {
+ return Object.prototype.hasOwnProperty.call(a, b);
+}
+
+function extend(a, b) {
+ for (var i in b) {
+ if (hasOwnProp(b, i)) {
+ a[i] = b[i];
+ }
+ }
+
+ if (hasOwnProp(b, 'toString')) {
+ a.toString = b.toString;
+ }
+
+ if (hasOwnProp(b, 'valueOf')) {
+ a.valueOf = b.valueOf;
+ }
+
+ return a;
+}
+
+function createUTC (input, format, locale, strict) {
+ return createLocalOrUTC(input, format, locale, strict, true).utc();
+}
+
+function defaultParsingFlags() {
+ // We need to deep clone this object.
+ return {
+ empty : false,
+ unusedTokens : [],
+ unusedInput : [],
+ overflow : -2,
+ charsLeftOver : 0,
+ nullInput : false,
+ invalidMonth : null,
+ invalidFormat : false,
+ userInvalidated : false,
+ iso : false,
+ parsedDateParts : [],
+ meridiem : null,
+ rfc2822 : false,
+ weekdayMismatch : false
+ };
+}
+
+function getParsingFlags(m) {
+ if (m._pf == null) {
+ m._pf = defaultParsingFlags();
+ }
+ return m._pf;
+}
+
+var some;
+if (Array.prototype.some) {
+ some = Array.prototype.some;
+} else {
+ some = function (fun) {
+ var t = Object(this);
+ var len = t.length >>> 0;
+
+ for (var i = 0; i < len; i++) {
+ if (i in t && fun.call(this, t[i], i, t)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+}
+
+var some$1 = some;
+
+function isValid(m) {
+ if (m._isValid == null) {
+ var flags = getParsingFlags(m);
+ var parsedParts = some$1.call(flags.parsedDateParts, function (i) {
+ return i != null;
+ });
+ var isNowValid = !isNaN(m._d.getTime()) &&
+ flags.overflow < 0 &&
+ !flags.empty &&
+ !flags.invalidMonth &&
+ !flags.invalidWeekday &&
+ !flags.nullInput &&
+ !flags.invalidFormat &&
+ !flags.userInvalidated &&
+ (!flags.meridiem || (flags.meridiem && parsedParts));
+
+ if (m._strict) {
+ isNowValid = isNowValid &&
+ flags.charsLeftOver === 0 &&
+ flags.unusedTokens.length === 0 &&
+ flags.bigHour === undefined;
+ }
+
+ if (Object.isFrozen == null || !Object.isFrozen(m)) {
+ m._isValid = isNowValid;
+ }
+ else {
+ return isNowValid;
+ }
+ }
+ return m._isValid;
+}
+
+function createInvalid (flags) {
+ var m = createUTC(NaN);
+ if (flags != null) {
+ extend(getParsingFlags(m), flags);
+ }
+ else {
+ getParsingFlags(m).userInvalidated = true;
+ }
+
+ return m;
+}
+
+// Plugins that add properties should also add the key here (null value),
+// so we can properly clone ourselves.
+var momentProperties = hooks.momentProperties = [];
+
+function copyConfig(to, from) {
+ var i, prop, val;
+
+ if (!isUndefined(from._isAMomentObject)) {
+ to._isAMomentObject = from._isAMomentObject;
+ }
+ if (!isUndefined(from._i)) {
+ to._i = from._i;
+ }
+ if (!isUndefined(from._f)) {
+ to._f = from._f;
+ }
+ if (!isUndefined(from._l)) {
+ to._l = from._l;
+ }
+ if (!isUndefined(from._strict)) {
+ to._strict = from._strict;
+ }
+ if (!isUndefined(from._tzm)) {
+ to._tzm = from._tzm;
+ }
+ if (!isUndefined(from._isUTC)) {
+ to._isUTC = from._isUTC;
+ }
+ if (!isUndefined(from._offset)) {
+ to._offset = from._offset;
+ }
+ if (!isUndefined(from._pf)) {
+ to._pf = getParsingFlags(from);
+ }
+ if (!isUndefined(from._locale)) {
+ to._locale = from._locale;
+ }
+
+ if (momentProperties.length > 0) {
+ for (i = 0; i < momentProperties.length; i++) {
+ prop = momentProperties[i];
+ val = from[prop];
+ if (!isUndefined(val)) {
+ to[prop] = val;
+ }
+ }
+ }
+
+ return to;
+}
+
+var updateInProgress = false;
+
+// Moment prototype object
+function Moment(config) {
+ copyConfig(this, config);
+ this._d = new Date(config._d != null ? config._d.getTime() : NaN);
+ if (!this.isValid()) {
+ this._d = new Date(NaN);
+ }
+ // Prevent infinite loop in case updateOffset creates new moment
+ // objects.
+ if (updateInProgress === false) {
+ updateInProgress = true;
+ hooks.updateOffset(this);
+ updateInProgress = false;
+ }
+}
+
+function isMoment (obj) {
+ return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
+}
+
+function absFloor (number) {
+ if (number < 0) {
+ // -0 -> 0
+ return Math.ceil(number) || 0;
+ } else {
+ return Math.floor(number);
+ }
+}
+
+function toInt(argumentForCoercion) {
+ var coercedNumber = +argumentForCoercion,
+ value = 0;
+
+ if (coercedNumber !== 0 && isFinite(coercedNumber)) {
+ value = absFloor(coercedNumber);
+ }
+
+ return value;
+}
+
+// compare two arrays, return the number of differences
+function compareArrays(array1, array2, dontConvert) {
+ var len = Math.min(array1.length, array2.length),
+ lengthDiff = Math.abs(array1.length - array2.length),
+ diffs = 0,
+ i;
+ for (i = 0; i < len; i++) {
+ if ((dontConvert && array1[i] !== array2[i]) ||
+ (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
+ diffs++;
+ }
+ }
+ return diffs + lengthDiff;
+}
+
+function warn(msg) {
+ if (hooks.suppressDeprecationWarnings === false &&
+ (typeof console !== 'undefined') && console.warn) {
+ console.warn('Deprecation warning: ' + msg);
+ }
+}
+
+function deprecate(msg, fn) {
+ var firstTime = true;
+
+ return extend(function () {
+ if (hooks.deprecationHandler != null) {
+ hooks.deprecationHandler(null, msg);
+ }
+ if (firstTime) {
+ var args = [];
+ var arg;
+ for (var i = 0; i < arguments.length; i++) {
+ arg = '';
+ if (typeof arguments[i] === 'object') {
+ arg += '\n[' + i + '] ';
+ for (var key in arguments[0]) {
+ arg += key + ': ' + arguments[0][key] + ', ';
+ }
+ arg = arg.slice(0, -2); // Remove trailing comma and space
+ } else {
+ arg = arguments[i];
+ }
+ args.push(arg);
+ }
+ warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
+ firstTime = false;
+ }
+ return fn.apply(this, arguments);
+ }, fn);
+}
+
+var deprecations = {};
+
+function deprecateSimple(name, msg) {
+ if (hooks.deprecationHandler != null) {
+ hooks.deprecationHandler(name, msg);
+ }
+ if (!deprecations[name]) {
+ warn(msg);
+ deprecations[name] = true;
+ }
+}
+
+hooks.suppressDeprecationWarnings = false;
+hooks.deprecationHandler = null;
+
+function isFunction(input) {
+ return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
+}
+
+function set (config) {
+ var prop, i;
+ for (i in config) {
+ prop = config[i];
+ if (isFunction(prop)) {
+ this[i] = prop;
+ } else {
+ this['_' + i] = prop;
+ }
+ }
+ this._config = config;
+ // Lenient ordinal parsing accepts just a number in addition to
+ // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
+ // TODO: Remove "ordinalParse" fallback in next major release.
+ this._dayOfMonthOrdinalParseLenient = new RegExp(
+ (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
+ '|' + (/\d{1,2}/).source);
+}
+
+function mergeConfigs(parentConfig, childConfig) {
+ var res = extend({}, parentConfig), prop;
+ for (prop in childConfig) {
+ if (hasOwnProp(childConfig, prop)) {
+ if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
+ res[prop] = {};
+ extend(res[prop], parentConfig[prop]);
+ extend(res[prop], childConfig[prop]);
+ } else if (childConfig[prop] != null) {
+ res[prop] = childConfig[prop];
+ } else {
+ delete res[prop];
+ }
+ }
+ }
+ for (prop in parentConfig) {
+ if (hasOwnProp(parentConfig, prop) &&
+ !hasOwnProp(childConfig, prop) &&
+ isObject(parentConfig[prop])) {
+ // make sure changes to properties don't modify parent config
+ res[prop] = extend({}, res[prop]);
+ }
+ }
+ return res;
+}
+
+function Locale(config) {
+ if (config != null) {
+ this.set(config);
+ }
+}
+
+var keys;
+
+if (Object.keys) {
+ keys = Object.keys;
+} else {
+ keys = function (obj) {
+ var i, res = [];
+ for (i in obj) {
+ if (hasOwnProp(obj, i)) {
+ res.push(i);
+ }
+ }
+ return res;
+ };
+}
+
+var keys$1 = keys;
+
+var defaultCalendar = {
+ sameDay : '[Today at] LT',
+ nextDay : '[Tomorrow at] LT',
+ nextWeek : 'dddd [at] LT',
+ lastDay : '[Yesterday at] LT',
+ lastWeek : '[Last] dddd [at] LT',
+ sameElse : 'L'
+};
+
+function calendar (key, mom, now) {
+ var output = this._calendar[key] || this._calendar['sameElse'];
+ return isFunction(output) ? output.call(mom, now) : output;
+}
+
+var defaultLongDateFormat = {
+ LTS : 'h:mm:ss A',
+ LT : 'h:mm A',
+ L : 'MM/DD/YYYY',
+ LL : 'MMMM D, YYYY',
+ LLL : 'MMMM D, YYYY h:mm A',
+ LLLL : 'dddd, MMMM D, YYYY h:mm A'
+};
+
+function longDateFormat (key) {
+ var format = this._longDateFormat[key],
+ formatUpper = this._longDateFormat[key.toUpperCase()];
+
+ if (format || !formatUpper) {
+ return format;
+ }
+
+ this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
+ return val.slice(1);
+ });
+
+ return this._longDateFormat[key];
+}
+
+var defaultInvalidDate = 'Invalid date';
+
+function invalidDate () {
+ return this._invalidDate;
+}
+
+var defaultOrdinal = '%d';
+var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
+
+function ordinal (number) {
+ return this._ordinal.replace('%d', number);
+}
+
+var defaultRelativeTime = {
+ future : 'in %s',
+ past : '%s ago',
+ s : 'a few seconds',
+ ss : '%d seconds',
+ m : 'a minute',
+ mm : '%d minutes',
+ h : 'an hour',
+ hh : '%d hours',
+ d : 'a day',
+ dd : '%d days',
+ M : 'a month',
+ MM : '%d months',
+ y : 'a year',
+ yy : '%d years'
+};
+
+function relativeTime (number, withoutSuffix, string, isFuture) {
+ var output = this._relativeTime[string];
+ return (isFunction(output)) ?
+ output(number, withoutSuffix, string, isFuture) :
+ output.replace(/%d/i, number);
+}
+
+function pastFuture (diff, output) {
+ var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
+ return isFunction(format) ? format(output) : format.replace(/%s/i, output);
+}
+
+var aliases = {};
+
+function addUnitAlias (unit, shorthand) {
+ var lowerCase = unit.toLowerCase();
+ aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
+}
+
+function normalizeUnits(units) {
+ return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
+}
+
+function normalizeObjectUnits(inputObject) {
+ var normalizedInput = {},
+ normalizedProp,
+ prop;
+
+ for (prop in inputObject) {
+ if (hasOwnProp(inputObject, prop)) {
+ normalizedProp = normalizeUnits(prop);
+ if (normalizedProp) {
+ normalizedInput[normalizedProp] = inputObject[prop];
+ }
+ }
+ }
+
+ return normalizedInput;
+}
+
+var priorities = {};
+
+function addUnitPriority(unit, priority) {
+ priorities[unit] = priority;
+}
+
+function getPrioritizedUnits(unitsObj) {
+ var units = [];
+ for (var u in unitsObj) {
+ units.push({unit: u, priority: priorities[u]});
+ }
+ units.sort(function (a, b) {
+ return a.priority - b.priority;
+ });
+ return units;
+}
+
+function makeGetSet (unit, keepTime) {
+ return function (value) {
+ if (value != null) {
+ set$1(this, unit, value);
+ hooks.updateOffset(this, keepTime);
+ return this;
+ } else {
+ return get(this, unit);
+ }
+ };
+}
+
+function get (mom, unit) {
+ return mom.isValid() ?
+ mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
+}
+
+function set$1 (mom, unit, value) {
+ if (mom.isValid()) {
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
+ }
+}
+
+// MOMENTS
+
+function stringGet (units) {
+ units = normalizeUnits(units);
+ if (isFunction(this[units])) {
+ return this[units]();
+ }
+ return this;
+}
+
+
+function stringSet (units, value) {
+ if (typeof units === 'object') {
+ units = normalizeObjectUnits(units);
+ var prioritized = getPrioritizedUnits(units);
+ for (var i = 0; i < prioritized.length; i++) {
+ this[prioritized[i].unit](units[prioritized[i].unit]);
+ }
+ } else {
+ units = normalizeUnits(units);
+ if (isFunction(this[units])) {
+ return this[units](value);
+ }
+ }
+ return this;
+}
+
+function zeroFill(number, targetLength, forceSign) {
+ var absNumber = '' + Math.abs(number),
+ zerosToFill = targetLength - absNumber.length,
+ sign = number >= 0;
+ return (sign ? (forceSign ? '+' : '') : '-') +
+ Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
+}
+
+var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
+
+var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
+
+var formatFunctions = {};
+
+var formatTokenFunctions = {};
+
+// token: 'M'
+// padded: ['MM', 2]
+// ordinal: 'Mo'
+// callback: function () { this.month() + 1 }
+function addFormatToken (token, padded, ordinal, callback) {
+ var func = callback;
+ if (typeof callback === 'string') {
+ func = function () {
+ return this[callback]();
+ };
+ }
+ if (token) {
+ formatTokenFunctions[token] = func;
+ }
+ if (padded) {
+ formatTokenFunctions[padded[0]] = function () {
+ return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
+ };
+ }
+ if (ordinal) {
+ formatTokenFunctions[ordinal] = function () {
+ return this.localeData().ordinal(func.apply(this, arguments), token);
+ };
+ }
+}
+
+function removeFormattingTokens(input) {
+ if (input.match(/\[[\s\S]/)) {
+ return input.replace(/^\[|\]$/g, '');
+ }
+ return input.replace(/\\/g, '');
+}
+
+function makeFormatFunction(format) {
+ var array = format.match(formattingTokens), i, length;
+
+ for (i = 0, length = array.length; i < length; i++) {
+ if (formatTokenFunctions[array[i]]) {
+ array[i] = formatTokenFunctions[array[i]];
+ } else {
+ array[i] = removeFormattingTokens(array[i]);
+ }
+ }
+
+ return function (mom) {
+ var output = '', i;
+ for (i = 0; i < length; i++) {
+ output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
+ }
+ return output;
+ };
+}
+
+// format date using native date object
+function formatMoment(m, format) {
+ if (!m.isValid()) {
+ return m.localeData().invalidDate();
+ }
+
+ format = expandFormat(format, m.localeData());
+ formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
+
+ return formatFunctions[format](m);
+}
+
+function expandFormat(format, locale) {
+ var i = 5;
+
+ function replaceLongDateFormatTokens(input) {
+ return locale.longDateFormat(input) || input;
+ }
+
+ localFormattingTokens.lastIndex = 0;
+ while (i >= 0 && localFormattingTokens.test(format)) {
+ format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
+ localFormattingTokens.lastIndex = 0;
+ i -= 1;
+ }
+
+ return format;
+}
+
+var match1 = /\d/; // 0 - 9
+var match2 = /\d\d/; // 00 - 99
+var match3 = /\d{3}/; // 000 - 999
+var match4 = /\d{4}/; // 0000 - 9999
+var match6 = /[+-]?\d{6}/; // -999999 - 999999
+var match1to2 = /\d\d?/; // 0 - 99
+var match3to4 = /\d\d\d\d?/; // 999 - 9999
+var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
+var match1to3 = /\d{1,3}/; // 0 - 999
+var match1to4 = /\d{1,4}/; // 0 - 9999
+var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
+
+var matchUnsigned = /\d+/; // 0 - inf
+var matchSigned = /[+-]?\d+/; // -inf - inf
+
+var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
+var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
+
+var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
+
+// any word (or two) characters or numbers including two/three word month in arabic.
+// includes scottish gaelic two word and hyphenated months
+var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
+
+
+var regexes = {};
+
+function addRegexToken (token, regex, strictRegex) {
+ regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
+ return (isStrict && strictRegex) ? strictRegex : regex;
+ };
+}
+
+function getParseRegexForToken (token, config) {
+ if (!hasOwnProp(regexes, token)) {
+ return new RegExp(unescapeFormat(token));
+ }
+
+ return regexes[token](config._strict, config._locale);
+}
+
+// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+function unescapeFormat(s) {
+ return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
+ return p1 || p2 || p3 || p4;
+ }));
+}
+
+function regexEscape(s) {
+ return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+}
+
+var tokens = {};
+
+function addParseToken (token, callback) {
+ var i, func = callback;
+ if (typeof token === 'string') {
+ token = [token];
+ }
+ if (isNumber(callback)) {
+ func = function (input, array) {
+ array[callback] = toInt(input);
+ };
+ }
+ for (i = 0; i < token.length; i++) {
+ tokens[token[i]] = func;
+ }
+}
+
+function addWeekParseToken (token, callback) {
+ addParseToken(token, function (input, array, config, token) {
+ config._w = config._w || {};
+ callback(input, config._w, config, token);
+ });
+}
+
+function addTimeToArrayFromToken(token, input, config) {
+ if (input != null && hasOwnProp(tokens, token)) {
+ tokens[token](input, config._a, config, token);
+ }
+}
+
+var YEAR = 0;
+var MONTH = 1;
+var DATE = 2;
+var HOUR = 3;
+var MINUTE = 4;
+var SECOND = 5;
+var MILLISECOND = 6;
+var WEEK = 7;
+var WEEKDAY = 8;
+
+var indexOf;
+
+if (Array.prototype.indexOf) {
+ indexOf = Array.prototype.indexOf;
+} else {
+ indexOf = function (o) {
+ // I know
+ var i;
+ for (i = 0; i < this.length; ++i) {
+ if (this[i] === o) {
+ return i;
+ }
+ }
+ return -1;
+ };
+}
+
+var indexOf$1 = indexOf;
+
+function daysInMonth(year, month) {
+ return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
+}
+
+// FORMATTING
+
+addFormatToken('M', ['MM', 2], 'Mo', function () {
+ return this.month() + 1;
+});
+
+addFormatToken('MMM', 0, 0, function (format) {
+ return this.localeData().monthsShort(this, format);
+});
+
+addFormatToken('MMMM', 0, 0, function (format) {
+ return this.localeData().months(this, format);
+});
+
+// ALIASES
+
+addUnitAlias('month', 'M');
+
+// PRIORITY
+
+addUnitPriority('month', 8);
+
+// PARSING
+
+addRegexToken('M', match1to2);
+addRegexToken('MM', match1to2, match2);
+addRegexToken('MMM', function (isStrict, locale) {
+ return locale.monthsShortRegex(isStrict);
+});
+addRegexToken('MMMM', function (isStrict, locale) {
+ return locale.monthsRegex(isStrict);
+});
+
+addParseToken(['M', 'MM'], function (input, array) {
+ array[MONTH] = toInt(input) - 1;
+});
+
+addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
+ var month = config._locale.monthsParse(input, token, config._strict);
+ // if we didn't find a month name, mark the date as invalid.
+ if (month != null) {
+ array[MONTH] = month;
+ } else {
+ getParsingFlags(config).invalidMonth = input;
+ }
+});
+
+// LOCALES
+
+var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
+var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
+function localeMonths (m, format) {
+ if (!m) {
+ return isArray(this._months) ? this._months :
+ this._months['standalone'];
+ }
+ return isArray(this._months) ? this._months[m.month()] :
+ this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
+function localeMonthsShort (m, format) {
+ if (!m) {
+ return isArray(this._monthsShort) ? this._monthsShort :
+ this._monthsShort['standalone'];
+ }
+ return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
+ this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
+}
+
+function handleStrictParse(monthName, format, strict) {
+ var i, ii, mom, llc = monthName.toLocaleLowerCase();
+ if (!this._monthsParse) {
+ // this is not used
+ this._monthsParse = [];
+ this._longMonthsParse = [];
+ this._shortMonthsParse = [];
+ for (i = 0; i < 12; ++i) {
+ mom = createUTC([2000, i]);
+ this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
+ this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
+ }
+ }
+
+ if (strict) {
+ if (format === 'MMM') {
+ ii = indexOf$1.call(this._shortMonthsParse, llc);
+ return ii !== -1 ? ii : null;
+ } else {
+ ii = indexOf$1.call(this._longMonthsParse, llc);
+ return ii !== -1 ? ii : null;
+ }
+ } else {
+ if (format === 'MMM') {
+ ii = indexOf$1.call(this._shortMonthsParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf$1.call(this._longMonthsParse, llc);
+ return ii !== -1 ? ii : null;
+ } else {
+ ii = indexOf$1.call(this._longMonthsParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf$1.call(this._shortMonthsParse, llc);
+ return ii !== -1 ? ii : null;
+ }
+ }
+}
+
+function localeMonthsParse (monthName, format, strict) {
+ var i, mom, regex;
+
+ if (this._monthsParseExact) {
+ return handleStrictParse.call(this, monthName, format, strict);
+ }
+
+ if (!this._monthsParse) {
+ this._monthsParse = [];
+ this._longMonthsParse = [];
+ this._shortMonthsParse = [];
+ }
+
+ // TODO: add sorting
+ // Sorting makes sure if one month (or abbr) is a prefix of another
+ // see sorting in computeMonthsParse
+ for (i = 0; i < 12; i++) {
+ // make the regex if we don't have it already
+ mom = createUTC([2000, i]);
+ if (strict && !this._longMonthsParse[i]) {
+ this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
+ this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
+ }
+ if (!strict && !this._monthsParse[i]) {
+ regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
+ this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
+ }
+ // test the regex
+ if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
+ return i;
+ } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
+ return i;
+ } else if (!strict && this._monthsParse[i].test(monthName)) {
+ return i;
+ }
+ }
+}
+
+// MOMENTS
+
+function setMonth (mom, value) {
+ var dayOfMonth;
+
+ if (!mom.isValid()) {
+ // No op
+ return mom;
+ }
+
+ if (typeof value === 'string') {
+ if (/^\d+$/.test(value)) {
+ value = toInt(value);
+ } else {
+ value = mom.localeData().monthsParse(value);
+ // TODO: Another silent failure?
+ if (!isNumber(value)) {
+ return mom;
+ }
+ }
+ }
+
+ dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
+ return mom;
+}
+
+function getSetMonth (value) {
+ if (value != null) {
+ setMonth(this, value);
+ hooks.updateOffset(this, true);
+ return this;
+ } else {
+ return get(this, 'Month');
+ }
+}
+
+function getDaysInMonth () {
+ return daysInMonth(this.year(), this.month());
+}
+
+var defaultMonthsShortRegex = matchWord;
+function monthsShortRegex (isStrict) {
+ if (this._monthsParseExact) {
+ if (!hasOwnProp(this, '_monthsRegex')) {
+ computeMonthsParse.call(this);
+ }
+ if (isStrict) {
+ return this._monthsShortStrictRegex;
+ } else {
+ return this._monthsShortRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_monthsShortRegex')) {
+ this._monthsShortRegex = defaultMonthsShortRegex;
+ }
+ return this._monthsShortStrictRegex && isStrict ?
+ this._monthsShortStrictRegex : this._monthsShortRegex;
+ }
+}
+
+var defaultMonthsRegex = matchWord;
+function monthsRegex (isStrict) {
+ if (this._monthsParseExact) {
+ if (!hasOwnProp(this, '_monthsRegex')) {
+ computeMonthsParse.call(this);
+ }
+ if (isStrict) {
+ return this._monthsStrictRegex;
+ } else {
+ return this._monthsRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_monthsRegex')) {
+ this._monthsRegex = defaultMonthsRegex;
+ }
+ return this._monthsStrictRegex && isStrict ?
+ this._monthsStrictRegex : this._monthsRegex;
+ }
+}
+
+function computeMonthsParse () {
+ function cmpLenRev(a, b) {
+ return b.length - a.length;
+ }
+
+ var shortPieces = [], longPieces = [], mixedPieces = [],
+ i, mom;
+ for (i = 0; i < 12; i++) {
+ // make the regex if we don't have it already
+ mom = createUTC([2000, i]);
+ shortPieces.push(this.monthsShort(mom, ''));
+ longPieces.push(this.months(mom, ''));
+ mixedPieces.push(this.months(mom, ''));
+ mixedPieces.push(this.monthsShort(mom, ''));
+ }
+ // Sorting makes sure if one month (or abbr) is a prefix of another it
+ // will match the longer piece.
+ shortPieces.sort(cmpLenRev);
+ longPieces.sort(cmpLenRev);
+ mixedPieces.sort(cmpLenRev);
+ for (i = 0; i < 12; i++) {
+ shortPieces[i] = regexEscape(shortPieces[i]);
+ longPieces[i] = regexEscape(longPieces[i]);
+ }
+ for (i = 0; i < 24; i++) {
+ mixedPieces[i] = regexEscape(mixedPieces[i]);
+ }
+
+ this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+ this._monthsShortRegex = this._monthsRegex;
+ this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+ this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+}
+
+// FORMATTING
+
+addFormatToken('Y', 0, 0, function () {
+ var y = this.year();
+ return y <= 9999 ? '' + y : '+' + y;
+});
+
+addFormatToken(0, ['YY', 2], 0, function () {
+ return this.year() % 100;
+});
+
+addFormatToken(0, ['YYYY', 4], 0, 'year');
+addFormatToken(0, ['YYYYY', 5], 0, 'year');
+addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
+
+// ALIASES
+
+addUnitAlias('year', 'y');
+
+// PRIORITIES
+
+addUnitPriority('year', 1);
+
+// PARSING
+
+addRegexToken('Y', matchSigned);
+addRegexToken('YY', match1to2, match2);
+addRegexToken('YYYY', match1to4, match4);
+addRegexToken('YYYYY', match1to6, match6);
+addRegexToken('YYYYYY', match1to6, match6);
+
+addParseToken(['YYYYY', 'YYYYYY'], YEAR);
+addParseToken('YYYY', function (input, array) {
+ array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
+});
+addParseToken('YY', function (input, array) {
+ array[YEAR] = hooks.parseTwoDigitYear(input);
+});
+addParseToken('Y', function (input, array) {
+ array[YEAR] = parseInt(input, 10);
+});
+
+// HELPERS
+
+function daysInYear(year) {
+ return isLeapYear(year) ? 366 : 365;
+}
+
+function isLeapYear(year) {
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+}
+
+// HOOKS
+
+hooks.parseTwoDigitYear = function (input) {
+ return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
+};
+
+// MOMENTS
+
+var getSetYear = makeGetSet('FullYear', true);
+
+function getIsLeapYear () {
+ return isLeapYear(this.year());
+}
+
+function createDate (y, m, d, h, M, s, ms) {
+ // can't just apply() to create a date:
+ // https://stackoverflow.com/q/181348
+ var date = new Date(y, m, d, h, M, s, ms);
+
+ // the date constructor remaps years 0-99 to 1900-1999
+ if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
+ date.setFullYear(y);
+ }
+ return date;
+}
+
+function createUTCDate (y) {
+ var date = new Date(Date.UTC.apply(null, arguments));
+
+ // the Date.UTC function remaps years 0-99 to 1900-1999
+ if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
+ date.setUTCFullYear(y);
+ }
+ return date;
+}
+
+// start-of-first-week - start-of-year
+function firstWeekOffset(year, dow, doy) {
+ var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
+ fwd = 7 + dow - doy,
+ // first-week day local weekday -- which local weekday is fwd
+ fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
+
+ return -fwdlw + fwd - 1;
+}
+
+// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
+ var localWeekday = (7 + weekday - dow) % 7,
+ weekOffset = firstWeekOffset(year, dow, doy),
+ dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
+ resYear, resDayOfYear;
+
+ if (dayOfYear <= 0) {
+ resYear = year - 1;
+ resDayOfYear = daysInYear(resYear) + dayOfYear;
+ } else if (dayOfYear > daysInYear(year)) {
+ resYear = year + 1;
+ resDayOfYear = dayOfYear - daysInYear(year);
+ } else {
+ resYear = year;
+ resDayOfYear = dayOfYear;
+ }
+
+ return {
+ year: resYear,
+ dayOfYear: resDayOfYear
+ };
+}
+
+function weekOfYear(mom, dow, doy) {
+ var weekOffset = firstWeekOffset(mom.year(), dow, doy),
+ week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
+ resWeek, resYear;
+
+ if (week < 1) {
+ resYear = mom.year() - 1;
+ resWeek = week + weeksInYear(resYear, dow, doy);
+ } else if (week > weeksInYear(mom.year(), dow, doy)) {
+ resWeek = week - weeksInYear(mom.year(), dow, doy);
+ resYear = mom.year() + 1;
+ } else {
+ resYear = mom.year();
+ resWeek = week;
+ }
+
+ return {
+ week: resWeek,
+ year: resYear
+ };
+}
+
+function weeksInYear(year, dow, doy) {
+ var weekOffset = firstWeekOffset(year, dow, doy),
+ weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
+ return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
+}
+
+// FORMATTING
+
+addFormatToken('w', ['ww', 2], 'wo', 'week');
+addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
+
+// ALIASES
+
+addUnitAlias('week', 'w');
+addUnitAlias('isoWeek', 'W');
+
+// PRIORITIES
+
+addUnitPriority('week', 5);
+addUnitPriority('isoWeek', 5);
+
+// PARSING
+
+addRegexToken('w', match1to2);
+addRegexToken('ww', match1to2, match2);
+addRegexToken('W', match1to2);
+addRegexToken('WW', match1to2, match2);
+
+addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
+ week[token.substr(0, 1)] = toInt(input);
+});
+
+// HELPERS
+
+// LOCALES
+
+function localeWeek (mom) {
+ return weekOfYear(mom, this._week.dow, this._week.doy).week;
+}
+
+var defaultLocaleWeek = {
+ dow : 0, // Sunday is the first day of the week.
+ doy : 6 // The week that contains Jan 1st is the first week of the year.
+};
+
+function localeFirstDayOfWeek () {
+ return this._week.dow;
+}
+
+function localeFirstDayOfYear () {
+ return this._week.doy;
+}
+
+// MOMENTS
+
+function getSetWeek (input) {
+ var week = this.localeData().week(this);
+ return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+function getSetISOWeek (input) {
+ var week = weekOfYear(this, 1, 4).week;
+ return input == null ? week : this.add((input - week) * 7, 'd');
+}
+
+// FORMATTING
+
+addFormatToken('d', 0, 'do', 'day');
+
+addFormatToken('dd', 0, 0, function (format) {
+ return this.localeData().weekdaysMin(this, format);
+});
+
+addFormatToken('ddd', 0, 0, function (format) {
+ return this.localeData().weekdaysShort(this, format);
+});
+
+addFormatToken('dddd', 0, 0, function (format) {
+ return this.localeData().weekdays(this, format);
+});
+
+addFormatToken('e', 0, 0, 'weekday');
+addFormatToken('E', 0, 0, 'isoWeekday');
+
+// ALIASES
+
+addUnitAlias('day', 'd');
+addUnitAlias('weekday', 'e');
+addUnitAlias('isoWeekday', 'E');
+
+// PRIORITY
+addUnitPriority('day', 11);
+addUnitPriority('weekday', 11);
+addUnitPriority('isoWeekday', 11);
+
+// PARSING
+
+addRegexToken('d', match1to2);
+addRegexToken('e', match1to2);
+addRegexToken('E', match1to2);
+addRegexToken('dd', function (isStrict, locale) {
+ return locale.weekdaysMinRegex(isStrict);
+});
+addRegexToken('ddd', function (isStrict, locale) {
+ return locale.weekdaysShortRegex(isStrict);
+});
+addRegexToken('dddd', function (isStrict, locale) {
+ return locale.weekdaysRegex(isStrict);
+});
+
+addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
+ var weekday = config._locale.weekdaysParse(input, token, config._strict);
+ // if we didn't get a weekday name, mark the date as invalid
+ if (weekday != null) {
+ week.d = weekday;
+ } else {
+ getParsingFlags(config).invalidWeekday = input;
+ }
+});
+
+addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
+ week[token] = toInt(input);
+});
+
+// HELPERS
+
+function parseWeekday(input, locale) {
+ if (typeof input !== 'string') {
+ return input;
+ }
+
+ if (!isNaN(input)) {
+ return parseInt(input, 10);
+ }
+
+ input = locale.weekdaysParse(input);
+ if (typeof input === 'number') {
+ return input;
+ }
+
+ return null;
+}
+
+function parseIsoWeekday(input, locale) {
+ if (typeof input === 'string') {
+ return locale.weekdaysParse(input) % 7 || 7;
+ }
+ return isNaN(input) ? null : input;
+}
+
+// LOCALES
+
+var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
+function localeWeekdays (m, format) {
+ if (!m) {
+ return isArray(this._weekdays) ? this._weekdays :
+ this._weekdays['standalone'];
+ }
+ return isArray(this._weekdays) ? this._weekdays[m.day()] :
+ this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
+}
+
+var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
+function localeWeekdaysShort (m) {
+ return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
+}
+
+var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
+function localeWeekdaysMin (m) {
+ return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
+}
+
+function handleStrictParse$1(weekdayName, format, strict) {
+ var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
+ if (!this._weekdaysParse) {
+ this._weekdaysParse = [];
+ this._shortWeekdaysParse = [];
+ this._minWeekdaysParse = [];
+
+ for (i = 0; i < 7; ++i) {
+ mom = createUTC([2000, 1]).day(i);
+ this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
+ this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
+ this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
+ }
+ }
+
+ if (strict) {
+ if (format === 'dddd') {
+ ii = indexOf$1.call(this._weekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ } else if (format === 'ddd') {
+ ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ } else {
+ ii = indexOf$1.call(this._minWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ }
+ } else {
+ if (format === 'dddd') {
+ ii = indexOf$1.call(this._weekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf$1.call(this._minWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ } else if (format === 'ddd') {
+ ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf$1.call(this._weekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf$1.call(this._minWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ } else {
+ ii = indexOf$1.call(this._minWeekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf$1.call(this._weekdaysParse, llc);
+ if (ii !== -1) {
+ return ii;
+ }
+ ii = indexOf$1.call(this._shortWeekdaysParse, llc);
+ return ii !== -1 ? ii : null;
+ }
+ }
+}
+
+function localeWeekdaysParse (weekdayName, format, strict) {
+ var i, mom, regex;
+
+ if (this._weekdaysParseExact) {
+ return handleStrictParse$1.call(this, weekdayName, format, strict);
+ }
+
+ if (!this._weekdaysParse) {
+ this._weekdaysParse = [];
+ this._minWeekdaysParse = [];
+ this._shortWeekdaysParse = [];
+ this._fullWeekdaysParse = [];
+ }
+
+ for (i = 0; i < 7; i++) {
+ // make the regex if we don't have it already
+
+ mom = createUTC([2000, 1]).day(i);
+ if (strict && !this._fullWeekdaysParse[i]) {
+ this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
+ this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
+ this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
+ }
+ if (!this._weekdaysParse[i]) {
+ regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
+ this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
+ }
+ // test the regex
+ if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
+ return i;
+ } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
+ return i;
+ } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
+ return i;
+ } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
+ return i;
+ }
+ }
+}
+
+// MOMENTS
+
+function getSetDayOfWeek (input) {
+ if (!this.isValid()) {
+ return input != null ? this : NaN;
+ }
+ var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
+ if (input != null) {
+ input = parseWeekday(input, this.localeData());
+ return this.add(input - day, 'd');
+ } else {
+ return day;
+ }
+}
+
+function getSetLocaleDayOfWeek (input) {
+ if (!this.isValid()) {
+ return input != null ? this : NaN;
+ }
+ var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
+ return input == null ? weekday : this.add(input - weekday, 'd');
+}
+
+function getSetISODayOfWeek (input) {
+ if (!this.isValid()) {
+ return input != null ? this : NaN;
+ }
+
+ // behaves the same as moment#day except
+ // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
+ // as a setter, sunday should belong to the previous week.
+
+ if (input != null) {
+ var weekday = parseIsoWeekday(input, this.localeData());
+ return this.day(this.day() % 7 ? weekday : weekday - 7);
+ } else {
+ return this.day() || 7;
+ }
+}
+
+var defaultWeekdaysRegex = matchWord;
+function weekdaysRegex (isStrict) {
+ if (this._weekdaysParseExact) {
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
+ computeWeekdaysParse.call(this);
+ }
+ if (isStrict) {
+ return this._weekdaysStrictRegex;
+ } else {
+ return this._weekdaysRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
+ this._weekdaysRegex = defaultWeekdaysRegex;
+ }
+ return this._weekdaysStrictRegex && isStrict ?
+ this._weekdaysStrictRegex : this._weekdaysRegex;
+ }
+}
+
+var defaultWeekdaysShortRegex = matchWord;
+function weekdaysShortRegex (isStrict) {
+ if (this._weekdaysParseExact) {
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
+ computeWeekdaysParse.call(this);
+ }
+ if (isStrict) {
+ return this._weekdaysShortStrictRegex;
+ } else {
+ return this._weekdaysShortRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_weekdaysShortRegex')) {
+ this._weekdaysShortRegex = defaultWeekdaysShortRegex;
+ }
+ return this._weekdaysShortStrictRegex && isStrict ?
+ this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
+ }
+}
+
+var defaultWeekdaysMinRegex = matchWord;
+function weekdaysMinRegex (isStrict) {
+ if (this._weekdaysParseExact) {
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
+ computeWeekdaysParse.call(this);
+ }
+ if (isStrict) {
+ return this._weekdaysMinStrictRegex;
+ } else {
+ return this._weekdaysMinRegex;
+ }
+ } else {
+ if (!hasOwnProp(this, '_weekdaysMinRegex')) {
+ this._weekdaysMinRegex = defaultWeekdaysMinRegex;
+ }
+ return this._weekdaysMinStrictRegex && isStrict ?
+ this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
+ }
+}
+
+
+function computeWeekdaysParse () {
+ function cmpLenRev(a, b) {
+ return b.length - a.length;
+ }
+
+ var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
+ i, mom, minp, shortp, longp;
+ for (i = 0; i < 7; i++) {
+ // make the regex if we don't have it already
+ mom = createUTC([2000, 1]).day(i);
+ minp = this.weekdaysMin(mom, '');
+ shortp = this.weekdaysShort(mom, '');
+ longp = this.weekdays(mom, '');
+ minPieces.push(minp);
+ shortPieces.push(shortp);
+ longPieces.push(longp);
+ mixedPieces.push(minp);
+ mixedPieces.push(shortp);
+ mixedPieces.push(longp);
+ }
+ // Sorting makes sure if one weekday (or abbr) is a prefix of another it
+ // will match the longer piece.
+ minPieces.sort(cmpLenRev);
+ shortPieces.sort(cmpLenRev);
+ longPieces.sort(cmpLenRev);
+ mixedPieces.sort(cmpLenRev);
+ for (i = 0; i < 7; i++) {
+ shortPieces[i] = regexEscape(shortPieces[i]);
+ longPieces[i] = regexEscape(longPieces[i]);
+ mixedPieces[i] = regexEscape(mixedPieces[i]);
+ }
+
+ this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+ this._weekdaysShortRegex = this._weekdaysRegex;
+ this._weekdaysMinRegex = this._weekdaysRegex;
+
+ this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
+ this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
+ this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
+}
+
+// FORMATTING
+
+function hFormat() {
+ return this.hours() % 12 || 12;
+}
+
+function kFormat() {
+ return this.hours() || 24;
+}
+
+addFormatToken('H', ['HH', 2], 0, 'hour');
+addFormatToken('h', ['hh', 2], 0, hFormat);
+addFormatToken('k', ['kk', 2], 0, kFormat);
+
+addFormatToken('hmm', 0, 0, function () {
+ return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('hmmss', 0, 0, function () {
+ return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
+ zeroFill(this.seconds(), 2);
+});
+
+addFormatToken('Hmm', 0, 0, function () {
+ return '' + this.hours() + zeroFill(this.minutes(), 2);
+});
+
+addFormatToken('Hmmss', 0, 0, function () {
+ return '' + this.hours() + zeroFill(this.minutes(), 2) +
+ zeroFill(this.seconds(), 2);
+});
+
+function meridiem (token, lowercase) {
+ addFormatToken(token, 0, 0, function () {
+ return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
+ });
+}
+
+meridiem('a', true);
+meridiem('A', false);
+
+// ALIASES
+
+addUnitAlias('hour', 'h');
+
+// PRIORITY
+addUnitPriority('hour', 13);
+
+// PARSING
+
+function matchMeridiem (isStrict, locale) {
+ return locale._meridiemParse;
+}
+
+addRegexToken('a', matchMeridiem);
+addRegexToken('A', matchMeridiem);
+addRegexToken('H', match1to2);
+addRegexToken('h', match1to2);
+addRegexToken('k', match1to2);
+addRegexToken('HH', match1to2, match2);
+addRegexToken('hh', match1to2, match2);
+addRegexToken('kk', match1to2, match2);
+
+addRegexToken('hmm', match3to4);
+addRegexToken('hmmss', match5to6);
+addRegexToken('Hmm', match3to4);
+addRegexToken('Hmmss', match5to6);
+
+addParseToken(['H', 'HH'], HOUR);
+addParseToken(['k', 'kk'], function (input, array, config) {
+ var kInput = toInt(input);
+ array[HOUR] = kInput === 24 ? 0 : kInput;
+});
+addParseToken(['a', 'A'], function (input, array, config) {
+ config._isPm = config._locale.isPM(input);
+ config._meridiem = input;
+});
+addParseToken(['h', 'hh'], function (input, array, config) {
+ array[HOUR] = toInt(input);
+ getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmm', function (input, array, config) {
+ var pos = input.length - 2;
+ array[HOUR] = toInt(input.substr(0, pos));
+ array[MINUTE] = toInt(input.substr(pos));
+ getParsingFlags(config).bigHour = true;
+});
+addParseToken('hmmss', function (input, array, config) {
+ var pos1 = input.length - 4;
+ var pos2 = input.length - 2;
+ array[HOUR] = toInt(input.substr(0, pos1));
+ array[MINUTE] = toInt(input.substr(pos1, 2));
+ array[SECOND] = toInt(input.substr(pos2));
+ getParsingFlags(config).bigHour = true;
+});
+addParseToken('Hmm', function (input, array, config) {
+ var pos = input.length - 2;
+ array[HOUR] = toInt(input.substr(0, pos));
+ array[MINUTE] = toInt(input.substr(pos));
+});
+addParseToken('Hmmss', function (input, array, config) {
+ var pos1 = input.length - 4;
+ var pos2 = input.length - 2;
+ array[HOUR] = toInt(input.substr(0, pos1));
+ array[MINUTE] = toInt(input.substr(pos1, 2));
+ array[SECOND] = toInt(input.substr(pos2));
+});
+
+// LOCALES
+
+function localeIsPM (input) {
+ // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
+ // Using charAt should be more compatible.
+ return ((input + '').toLowerCase().charAt(0) === 'p');
+}
+
+var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
+function localeMeridiem (hours, minutes, isLower) {
+ if (hours > 11) {
+ return isLower ? 'pm' : 'PM';
+ } else {
+ return isLower ? 'am' : 'AM';
+ }
+}
+
+
+// MOMENTS
+
+// Setting the hour should keep the time, because the user explicitly
+// specified which hour he wants. So trying to maintain the same hour (in
+// a new timezone) makes sense. Adding/subtracting hours does not follow
+// this rule.
+var getSetHour = makeGetSet('Hours', true);
+
+// months
+// week
+// weekdays
+// meridiem
+var baseConfig = {
+ calendar: defaultCalendar,
+ longDateFormat: defaultLongDateFormat,
+ invalidDate: defaultInvalidDate,
+ ordinal: defaultOrdinal,
+ dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
+ relativeTime: defaultRelativeTime,
+
+ months: defaultLocaleMonths,
+ monthsShort: defaultLocaleMonthsShort,
+
+ week: defaultLocaleWeek,
+
+ weekdays: defaultLocaleWeekdays,
+ weekdaysMin: defaultLocaleWeekdaysMin,
+ weekdaysShort: defaultLocaleWeekdaysShort,
+
+ meridiemParse: defaultLocaleMeridiemParse
+};
+
+// internal storage for locale config files
+var locales = {};
+var localeFamilies = {};
+var globalLocale;
+
+function normalizeLocale(key) {
+ return key ? key.toLowerCase().replace('_', '-') : key;
+}
+
+// pick the locale from the array
+// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
+// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
+function chooseLocale(names) {
+ var i = 0, j, next, locale, split;
+
+ while (i < names.length) {
+ split = normalizeLocale(names[i]).split('-');
+ j = split.length;
+ next = normalizeLocale(names[i + 1]);
+ next = next ? next.split('-') : null;
+ while (j > 0) {
+ locale = loadLocale(split.slice(0, j).join('-'));
+ if (locale) {
+ return locale;
+ }
+ if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
+ //the next array item is better than a shallower substring of this one
+ break;
+ }
+ j--;
+ }
+ i++;
+ }
+ return null;
+}
+
+function loadLocale(name) {
+ var oldLocale = null;
+ // TODO: Find a better way to register and load all the locales in Node
+ if (!locales[name] && (typeof module !== 'undefined') &&
+ module && module.exports) {
+ try {
+ oldLocale = globalLocale._abbr;
+ require('./locale/' + name);
+ // because defineLocale currently also sets the global locale, we
+ // want to undo that for lazy loaded locales
+ getSetGlobalLocale(oldLocale);
+ } catch (e) { }
+ }
+ return locales[name];
+}
+
+// This function will load locale and then set the global locale. If
+// no arguments are passed in, it will simply return the current global
+// locale key.
+function getSetGlobalLocale (key, values) {
+ var data;
+ if (key) {
+ if (isUndefined(values)) {
+ data = getLocale(key);
+ }
+ else {
+ data = defineLocale(key, values);
+ }
+
+ if (data) {
+ // moment.duration._locale = moment._locale = data;
+ globalLocale = data;
+ }
+ }
+
+ return globalLocale._abbr;
+}
+
+function defineLocale (name, config) {
+ if (config !== null) {
+ var parentConfig = baseConfig;
+ config.abbr = name;
+ if (locales[name] != null) {
+ deprecateSimple('defineLocaleOverride',
+ 'use moment.updateLocale(localeName, config) to change ' +
+ 'an existing locale. moment.defineLocale(localeName, ' +
+ 'config) should only be used for creating a new locale ' +
+ 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
+ parentConfig = locales[name]._config;
+ } else if (config.parentLocale != null) {
+ if (locales[config.parentLocale] != null) {
+ parentConfig = locales[config.parentLocale]._config;
+ } else {
+ if (!localeFamilies[config.parentLocale]) {
+ localeFamilies[config.parentLocale] = [];
+ }
+ localeFamilies[config.parentLocale].push({
+ name: name,
+ config: config
+ });
+ return null;
+ }
+ }
+ locales[name] = new Locale(mergeConfigs(parentConfig, config));
+
+ if (localeFamilies[name]) {
+ localeFamilies[name].forEach(function (x) {
+ defineLocale(x.name, x.config);
+ });
+ }
+
+ // backwards compat for now: also set the locale
+ // make sure we set the locale AFTER all child locales have been
+ // created, so we won't end up with the child locale set.
+ getSetGlobalLocale(name);
+
+
+ return locales[name];
+ } else {
+ // useful for testing
+ delete locales[name];
+ return null;
+ }
+}
+
+function updateLocale(name, config) {
+ if (config != null) {
+ var locale, parentConfig = baseConfig;
+ // MERGE
+ if (locales[name] != null) {
+ parentConfig = locales[name]._config;
+ }
+ config = mergeConfigs(parentConfig, config);
+ locale = new Locale(config);
+ locale.parentLocale = locales[name];
+ locales[name] = locale;
+
+ // backwards compat for now: also set the locale
+ getSetGlobalLocale(name);
+ } else {
+ // pass null for config to unupdate, useful for tests
+ if (locales[name] != null) {
+ if (locales[name].parentLocale != null) {
+ locales[name] = locales[name].parentLocale;
+ } else if (locales[name] != null) {
+ delete locales[name];
+ }
+ }
+ }
+ return locales[name];
+}
+
+// returns locale data
+function getLocale (key) {
+ var locale;
+
+ if (key && key._locale && key._locale._abbr) {
+ key = key._locale._abbr;
+ }
+
+ if (!key) {
+ return globalLocale;
+ }
+
+ if (!isArray(key)) {
+ //short-circuit everything else
+ locale = loadLocale(key);
+ if (locale) {
+ return locale;
+ }
+ key = [key];
+ }
+
+ return chooseLocale(key);
+}
+
+function listLocales() {
+ return keys$1(locales);
+}
+
+function checkOverflow (m) {
+ var overflow;
+ var a = m._a;
+
+ if (a && getParsingFlags(m).overflow === -2) {
+ overflow =
+ a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
+ a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
+ a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
+ a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
+ a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
+ a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
+ -1;
+
+ if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
+ overflow = DATE;
+ }
+ if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
+ overflow = WEEK;
+ }
+ if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
+ overflow = WEEKDAY;
+ }
+
+ getParsingFlags(m).overflow = overflow;
+ }
+
+ return m;
+}
+
+// iso 8601 regex
+// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
+var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+
+var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
+
+var isoDates = [
+ ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
+ ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
+ ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
+ ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
+ ['YYYY-DDD', /\d{4}-\d{3}/],
+ ['YYYY-MM', /\d{4}-\d\d/, false],
+ ['YYYYYYMMDD', /[+-]\d{10}/],
+ ['YYYYMMDD', /\d{8}/],
+ // YYYYMM is NOT allowed by the standard
+ ['GGGG[W]WWE', /\d{4}W\d{3}/],
+ ['GGGG[W]WW', /\d{4}W\d{2}/, false],
+ ['YYYYDDD', /\d{7}/]
+];
+
+// iso time formats and regexes
+var isoTimes = [
+ ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
+ ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
+ ['HH:mm:ss', /\d\d:\d\d:\d\d/],
+ ['HH:mm', /\d\d:\d\d/],
+ ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
+ ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
+ ['HHmmss', /\d\d\d\d\d\d/],
+ ['HHmm', /\d\d\d\d/],
+ ['HH', /\d\d/]
+];
+
+var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
+
+// date from iso format
+function configFromISO(config) {
+ var i, l,
+ string = config._i,
+ match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
+ allowTime, dateFormat, timeFormat, tzFormat;
+
+ if (match) {
+ getParsingFlags(config).iso = true;
+
+ for (i = 0, l = isoDates.length; i < l; i++) {
+ if (isoDates[i][1].exec(match[1])) {
+ dateFormat = isoDates[i][0];
+ allowTime = isoDates[i][2] !== false;
+ break;
+ }
+ }
+ if (dateFormat == null) {
+ config._isValid = false;
+ return;
+ }
+ if (match[3]) {
+ for (i = 0, l = isoTimes.length; i < l; i++) {
+ if (isoTimes[i][1].exec(match[3])) {
+ // match[2] should be 'T' or space
+ timeFormat = (match[2] || ' ') + isoTimes[i][0];
+ break;
+ }
+ }
+ if (timeFormat == null) {
+ config._isValid = false;
+ return;
+ }
+ }
+ if (!allowTime && timeFormat != null) {
+ config._isValid = false;
+ return;
+ }
+ if (match[4]) {
+ if (tzRegex.exec(match[4])) {
+ tzFormat = 'Z';
+ } else {
+ config._isValid = false;
+ return;
+ }
+ }
+ config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
+ configFromStringAndFormat(config);
+ } else {
+ config._isValid = false;
+ }
+}
+
+// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
+var basicRfcRegex = /^((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d?\d\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?:\d\d)?\d\d\s)(\d\d:\d\d)(\:\d\d)?(\s(?:UT|GMT|[ECMP][SD]T|[A-IK-Za-ik-z]|[+-]\d{4}))$/;
+
+// date and time from ref 2822 format
+function configFromRFC2822(config) {
+ var string, match, dayFormat,
+ dateFormat, timeFormat, tzFormat;
+ var timezones = {
+ ' GMT': ' +0000',
+ ' EDT': ' -0400',
+ ' EST': ' -0500',
+ ' CDT': ' -0500',
+ ' CST': ' -0600',
+ ' MDT': ' -0600',
+ ' MST': ' -0700',
+ ' PDT': ' -0700',
+ ' PST': ' -0800'
+ };
+ var military = 'YXWVUTSRQPONZABCDEFGHIKLM';
+ var timezone, timezoneIndex;
+
+ string = config._i
+ .replace(/\([^\)]*\)|[\n\t]/g, ' ') // Remove comments and folding whitespace
+ .replace(/(\s\s+)/g, ' ') // Replace multiple-spaces with a single space
+ .replace(/^\s|\s$/g, ''); // Remove leading and trailing spaces
+ match = basicRfcRegex.exec(string);
+
+ if (match) {
+ dayFormat = match[1] ? 'ddd' + ((match[1].length === 5) ? ', ' : ' ') : '';
+ dateFormat = 'D MMM ' + ((match[2].length > 10) ? 'YYYY ' : 'YY ');
+ timeFormat = 'HH:mm' + (match[4] ? ':ss' : '');
+
+ // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
+ if (match[1]) { // day of week given
+ var momentDate = new Date(match[2]);
+ var momentDay = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][momentDate.getDay()];
+
+ if (match[1].substr(0,3) !== momentDay) {
+ getParsingFlags(config).weekdayMismatch = true;
+ config._isValid = false;
+ return;
+ }
+ }
+
+ switch (match[5].length) {
+ case 2: // military
+ if (timezoneIndex === 0) {
+ timezone = ' +0000';
+ } else {
+ timezoneIndex = military.indexOf(match[5][1].toUpperCase()) - 12;
+ timezone = ((timezoneIndex < 0) ? ' -' : ' +') +
+ (('' + timezoneIndex).replace(/^-?/, '0')).match(/..$/)[0] + '00';
+ }
+ break;
+ case 4: // Zone
+ timezone = timezones[match[5]];
+ break;
+ default: // UT or +/-9999
+ timezone = timezones[' GMT'];
+ }
+ match[5] = timezone;
+ config._i = match.splice(1).join('');
+ tzFormat = ' ZZ';
+ config._f = dayFormat + dateFormat + timeFormat + tzFormat;
+ configFromStringAndFormat(config);
+ getParsingFlags(config).rfc2822 = true;
+ } else {
+ config._isValid = false;
+ }
+}
+
+// date from iso format or fallback
+function configFromString(config) {
+ var matched = aspNetJsonRegex.exec(config._i);
+
+ if (matched !== null) {
+ config._d = new Date(+matched[1]);
+ return;
+ }
+
+ configFromISO(config);
+ if (config._isValid === false) {
+ delete config._isValid;
+ } else {
+ return;
+ }
+
+ configFromRFC2822(config);
+ if (config._isValid === false) {
+ delete config._isValid;
+ } else {
+ return;
+ }
+
+ // Final attempt, use Input Fallback
+ hooks.createFromInputFallback(config);
+}
+
+hooks.createFromInputFallback = deprecate(
+ 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
+ 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
+ 'discouraged and will be removed in an upcoming major release. Please refer to ' +
+ 'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
+ function (config) {
+ config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
+ }
+);
+
+// Pick the first defined of two or three arguments.
+function defaults(a, b, c) {
+ if (a != null) {
+ return a;
+ }
+ if (b != null) {
+ return b;
+ }
+ return c;
+}
+
+function currentDateArray(config) {
+ // hooks is actually the exported moment object
+ var nowValue = new Date(hooks.now());
+ if (config._useUTC) {
+ return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
+ }
+ return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
+}
+
+// convert an array to a date.
+// the array should mirror the parameters below
+// note: all values past the year are optional and will default to the lowest possible value.
+// [year, month, day , hour, minute, second, millisecond]
+function configFromArray (config) {
+ var i, date, input = [], currentDate, yearToUse;
+
+ if (config._d) {
+ return;
+ }
+
+ currentDate = currentDateArray(config);
+
+ //compute day of the year from weeks and weekdays
+ if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
+ dayOfYearFromWeekInfo(config);
+ }
+
+ //if the day of the year is set, figure out what it is
+ if (config._dayOfYear != null) {
+ yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
+
+ if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
+ getParsingFlags(config)._overflowDayOfYear = true;
+ }
+
+ date = createUTCDate(yearToUse, 0, config._dayOfYear);
+ config._a[MONTH] = date.getUTCMonth();
+ config._a[DATE] = date.getUTCDate();
+ }
+
+ // Default to current date.
+ // * if no year, month, day of month are given, default to today
+ // * if day of month is given, default month and year
+ // * if month is given, default only year
+ // * if year is given, don't default anything
+ for (i = 0; i < 3 && config._a[i] == null; ++i) {
+ config._a[i] = input[i] = currentDate[i];
+ }
+
+ // Zero out whatever was not defaulted, including time
+ for (; i < 7; i++) {
+ config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
+ }
+
+ // Check for 24:00:00.000
+ if (config._a[HOUR] === 24 &&
+ config._a[MINUTE] === 0 &&
+ config._a[SECOND] === 0 &&
+ config._a[MILLISECOND] === 0) {
+ config._nextDay = true;
+ config._a[HOUR] = 0;
+ }
+
+ config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
+ // Apply timezone offset from input. The actual utcOffset can be changed
+ // with parseZone.
+ if (config._tzm != null) {
+ config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+ }
+
+ if (config._nextDay) {
+ config._a[HOUR] = 24;
+ }
+}
+
+function dayOfYearFromWeekInfo(config) {
+ var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
+
+ w = config._w;
+ if (w.GG != null || w.W != null || w.E != null) {
+ dow = 1;
+ doy = 4;
+
+ // TODO: We need to take the current isoWeekYear, but that depends on
+ // how we interpret now (local, utc, fixed offset). So create
+ // a now version of current config (take local/utc/offset flags, and
+ // create now).
+ weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
+ week = defaults(w.W, 1);
+ weekday = defaults(w.E, 1);
+ if (weekday < 1 || weekday > 7) {
+ weekdayOverflow = true;
+ }
+ } else {
+ dow = config._locale._week.dow;
+ doy = config._locale._week.doy;
+
+ var curWeek = weekOfYear(createLocal(), dow, doy);
+
+ weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
+
+ // Default to current week.
+ week = defaults(w.w, curWeek.week);
+
+ if (w.d != null) {
+ // weekday -- low day numbers are considered next week
+ weekday = w.d;
+ if (weekday < 0 || weekday > 6) {
+ weekdayOverflow = true;
+ }
+ } else if (w.e != null) {
+ // local weekday -- counting starts from begining of week
+ weekday = w.e + dow;
+ if (w.e < 0 || w.e > 6) {
+ weekdayOverflow = true;
+ }
+ } else {
+ // default to begining of week
+ weekday = dow;
+ }
+ }
+ if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
+ getParsingFlags(config)._overflowWeeks = true;
+ } else if (weekdayOverflow != null) {
+ getParsingFlags(config)._overflowWeekday = true;
+ } else {
+ temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
+ config._a[YEAR] = temp.year;
+ config._dayOfYear = temp.dayOfYear;
+ }
+}
+
+// constant that refers to the ISO standard
+hooks.ISO_8601 = function () {};
+
+// constant that refers to the RFC 2822 form
+hooks.RFC_2822 = function () {};
+
+// date from string and format string
+function configFromStringAndFormat(config) {
+ // TODO: Move this to another part of the creation flow to prevent circular deps
+ if (config._f === hooks.ISO_8601) {
+ configFromISO(config);
+ return;
+ }
+ if (config._f === hooks.RFC_2822) {
+ configFromRFC2822(config);
+ return;
+ }
+ config._a = [];
+ getParsingFlags(config).empty = true;
+
+ // This array is used to make a Date, either with `new Date` or `Date.UTC`
+ var string = '' + config._i,
+ i, parsedInput, tokens, token, skipped,
+ stringLength = string.length,
+ totalParsedInputLength = 0;
+
+ tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
+
+ for (i = 0; i < tokens.length; i++) {
+ token = tokens[i];
+ parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
+ // console.log('token', token, 'parsedInput', parsedInput,
+ // 'regex', getParseRegexForToken(token, config));
+ if (parsedInput) {
+ skipped = string.substr(0, string.indexOf(parsedInput));
+ if (skipped.length > 0) {
+ getParsingFlags(config).unusedInput.push(skipped);
+ }
+ string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
+ totalParsedInputLength += parsedInput.length;
+ }
+ // don't parse if it's not a known token
+ if (formatTokenFunctions[token]) {
+ if (parsedInput) {
+ getParsingFlags(config).empty = false;
+ }
+ else {
+ getParsingFlags(config).unusedTokens.push(token);
+ }
+ addTimeToArrayFromToken(token, parsedInput, config);
+ }
+ else if (config._strict && !parsedInput) {
+ getParsingFlags(config).unusedTokens.push(token);
+ }
+ }
+
+ // add remaining unparsed input length to the string
+ getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
+ if (string.length > 0) {
+ getParsingFlags(config).unusedInput.push(string);
+ }
+
+ // clear _12h flag if hour is <= 12
+ if (config._a[HOUR] <= 12 &&
+ getParsingFlags(config).bigHour === true &&
+ config._a[HOUR] > 0) {
+ getParsingFlags(config).bigHour = undefined;
+ }
+
+ getParsingFlags(config).parsedDateParts = config._a.slice(0);
+ getParsingFlags(config).meridiem = config._meridiem;
+ // handle meridiem
+ config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
+
+ configFromArray(config);
+ checkOverflow(config);
+}
+
+
+function meridiemFixWrap (locale, hour, meridiem) {
+ var isPm;
+
+ if (meridiem == null) {
+ // nothing to do
+ return hour;
+ }
+ if (locale.meridiemHour != null) {
+ return locale.meridiemHour(hour, meridiem);
+ } else if (locale.isPM != null) {
+ // Fallback
+ isPm = locale.isPM(meridiem);
+ if (isPm && hour < 12) {
+ hour += 12;
+ }
+ if (!isPm && hour === 12) {
+ hour = 0;
+ }
+ return hour;
+ } else {
+ // this is not supposed to happen
+ return hour;
+ }
+}
+
+// date from string and array of format strings
+function configFromStringAndArray(config) {
+ var tempConfig,
+ bestMoment,
+
+ scoreToBeat,
+ i,
+ currentScore;
+
+ if (config._f.length === 0) {
+ getParsingFlags(config).invalidFormat = true;
+ config._d = new Date(NaN);
+ return;
+ }
+
+ for (i = 0; i < config._f.length; i++) {
+ currentScore = 0;
+ tempConfig = copyConfig({}, config);
+ if (config._useUTC != null) {
+ tempConfig._useUTC = config._useUTC;
+ }
+ tempConfig._f = config._f[i];
+ configFromStringAndFormat(tempConfig);
+
+ if (!isValid(tempConfig)) {
+ continue;
+ }
+
+ // if there is any input that was not parsed add a penalty for that format
+ currentScore += getParsingFlags(tempConfig).charsLeftOver;
+
+ //or tokens
+ currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
+
+ getParsingFlags(tempConfig).score = currentScore;
+
+ if (scoreToBeat == null || currentScore < scoreToBeat) {
+ scoreToBeat = currentScore;
+ bestMoment = tempConfig;
+ }
+ }
+
+ extend(config, bestMoment || tempConfig);
+}
+
+function configFromObject(config) {
+ if (config._d) {
+ return;
+ }
+
+ var i = normalizeObjectUnits(config._i);
+ config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
+ return obj && parseInt(obj, 10);
+ });
+
+ configFromArray(config);
+}
+
+function createFromConfig (config) {
+ var res = new Moment(checkOverflow(prepareConfig(config)));
+ if (res._nextDay) {
+ // Adding is smart enough around DST
+ res.add(1, 'd');
+ res._nextDay = undefined;
+ }
+
+ return res;
+}
+
+function prepareConfig (config) {
+ var input = config._i,
+ format = config._f;
+
+ config._locale = config._locale || getLocale(config._l);
+
+ if (input === null || (format === undefined && input === '')) {
+ return createInvalid({nullInput: true});
+ }
+
+ if (typeof input === 'string') {
+ config._i = input = config._locale.preparse(input);
+ }
+
+ if (isMoment(input)) {
+ return new Moment(checkOverflow(input));
+ } else if (isDate(input)) {
+ config._d = input;
+ } else if (isArray(format)) {
+ configFromStringAndArray(config);
+ } else if (format) {
+ configFromStringAndFormat(config);
+ } else {
+ configFromInput(config);
+ }
+
+ if (!isValid(config)) {
+ config._d = null;
+ }
+
+ return config;
+}
+
+function configFromInput(config) {
+ var input = config._i;
+ if (isUndefined(input)) {
+ config._d = new Date(hooks.now());
+ } else if (isDate(input)) {
+ config._d = new Date(input.valueOf());
+ } else if (typeof input === 'string') {
+ configFromString(config);
+ } else if (isArray(input)) {
+ config._a = map(input.slice(0), function (obj) {
+ return parseInt(obj, 10);
+ });
+ configFromArray(config);
+ } else if (isObject(input)) {
+ configFromObject(config);
+ } else if (isNumber(input)) {
+ // from milliseconds
+ config._d = new Date(input);
+ } else {
+ hooks.createFromInputFallback(config);
+ }
+}
+
+function createLocalOrUTC (input, format, locale, strict, isUTC) {
+ var c = {};
+
+ if (locale === true || locale === false) {
+ strict = locale;
+ locale = undefined;
+ }
+
+ if ((isObject(input) && isObjectEmpty(input)) ||
+ (isArray(input) && input.length === 0)) {
+ input = undefined;
+ }
+ // object construction must be done this way.
+ // https://github.com/moment/moment/issues/1423
+ c._isAMomentObject = true;
+ c._useUTC = c._isUTC = isUTC;
+ c._l = locale;
+ c._i = input;
+ c._f = format;
+ c._strict = strict;
+
+ return createFromConfig(c);
+}
+
+function createLocal (input, format, locale, strict) {
+ return createLocalOrUTC(input, format, locale, strict, false);
+}
+
+var prototypeMin = deprecate(
+ 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
+ function () {
+ var other = createLocal.apply(null, arguments);
+ if (this.isValid() && other.isValid()) {
+ return other < this ? this : other;
+ } else {
+ return createInvalid();
+ }
+ }
+);
+
+var prototypeMax = deprecate(
+ 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
+ function () {
+ var other = createLocal.apply(null, arguments);
+ if (this.isValid() && other.isValid()) {
+ return other > this ? this : other;
+ } else {
+ return createInvalid();
+ }
+ }
+);
+
+// Pick a moment m from moments so that m[fn](other) is true for all
+// other. This relies on the function fn to be transitive.
+//
+// moments should either be an array of moment objects or an array, whose
+// first element is an array of moment objects.
+function pickBy(fn, moments) {
+ var res, i;
+ if (moments.length === 1 && isArray(moments[0])) {
+ moments = moments[0];
+ }
+ if (!moments.length) {
+ return createLocal();
+ }
+ res = moments[0];
+ for (i = 1; i < moments.length; ++i) {
+ if (!moments[i].isValid() || moments[i][fn](res)) {
+ res = moments[i];
+ }
+ }
+ return res;
+}
+
+// TODO: Use [].sort instead?
+function min () {
+ var args = [].slice.call(arguments, 0);
+
+ return pickBy('isBefore', args);
+}
+
+function max () {
+ var args = [].slice.call(arguments, 0);
+
+ return pickBy('isAfter', args);
+}
+
+var now = function () {
+ return Date.now ? Date.now() : +(new Date());
+};
+
+var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
+
+function isDurationValid(m) {
+ for (var key in m) {
+ if (!(ordering.indexOf(key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
+ return false;
+ }
+ }
+
+ var unitHasDecimal = false;
+ for (var i = 0; i < ordering.length; ++i) {
+ if (m[ordering[i]]) {
+ if (unitHasDecimal) {
+ return false; // only allow non-integers for smallest unit
+ }
+ if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
+ unitHasDecimal = true;
+ }
+ }
+ }
+
+ return true;
+}
+
+function isValid$1() {
+ return this._isValid;
+}
+
+function createInvalid$1() {
+ return createDuration(NaN);
+}
+
+function Duration (duration) {
+ var normalizedInput = normalizeObjectUnits(duration),
+ years = normalizedInput.year || 0,
+ quarters = normalizedInput.quarter || 0,
+ months = normalizedInput.month || 0,
+ weeks = normalizedInput.week || 0,
+ days = normalizedInput.day || 0,
+ hours = normalizedInput.hour || 0,
+ minutes = normalizedInput.minute || 0,
+ seconds = normalizedInput.second || 0,
+ milliseconds = normalizedInput.millisecond || 0;
+
+ this._isValid = isDurationValid(normalizedInput);
+
+ // representation for dateAddRemove
+ this._milliseconds = +milliseconds +
+ seconds * 1e3 + // 1000
+ minutes * 6e4 + // 1000 * 60
+ hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
+ // Because of dateAddRemove treats 24 hours as different from a
+ // day when working around DST, we need to store them separately
+ this._days = +days +
+ weeks * 7;
+ // It is impossible translate months into days without knowing
+ // which months you are are talking about, so we have to store
+ // it separately.
+ this._months = +months +
+ quarters * 3 +
+ years * 12;
+
+ this._data = {};
+
+ this._locale = getLocale();
+
+ this._bubble();
+}
+
+function isDuration (obj) {
+ return obj instanceof Duration;
+}
+
+function absRound (number) {
+ if (number < 0) {
+ return Math.round(-1 * number) * -1;
+ } else {
+ return Math.round(number);
+ }
+}
+
+// FORMATTING
+
+function offset (token, separator) {
+ addFormatToken(token, 0, 0, function () {
+ var offset = this.utcOffset();
+ var sign = '+';
+ if (offset < 0) {
+ offset = -offset;
+ sign = '-';
+ }
+ return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
+ });
+}
+
+offset('Z', ':');
+offset('ZZ', '');
+
+// PARSING
+
+addRegexToken('Z', matchShortOffset);
+addRegexToken('ZZ', matchShortOffset);
+addParseToken(['Z', 'ZZ'], function (input, array, config) {
+ config._useUTC = true;
+ config._tzm = offsetFromString(matchShortOffset, input);
+});
+
+// HELPERS
+
+// timezone chunker
+// '+10:00' > ['10', '00']
+// '-1530' > ['-15', '30']
+var chunkOffset = /([\+\-]|\d\d)/gi;
+
+function offsetFromString(matcher, string) {
+ var matches = (string || '').match(matcher);
+
+ if (matches === null) {
+ return null;
+ }
+
+ var chunk = matches[matches.length - 1] || [];
+ var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
+ var minutes = +(parts[1] * 60) + toInt(parts[2]);
+
+ return minutes === 0 ?
+ 0 :
+ parts[0] === '+' ? minutes : -minutes;
+}
+
+// Return a moment from input, that is local/utc/zone equivalent to model.
+function cloneWithOffset(input, model) {
+ var res, diff;
+ if (model._isUTC) {
+ res = model.clone();
+ diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
+ // Use low-level api, because this fn is low-level api.
+ res._d.setTime(res._d.valueOf() + diff);
+ hooks.updateOffset(res, false);
+ return res;
+ } else {
+ return createLocal(input).local();
+ }
+}
+
+function getDateOffset (m) {
+ // On Firefox.24 Date#getTimezoneOffset returns a floating point.
+ // https://github.com/moment/moment/pull/1871
+ return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
+}
+
+// HOOKS
+
+// This function will be called whenever a moment is mutated.
+// It is intended to keep the offset in sync with the timezone.
+hooks.updateOffset = function () {};
+
+// MOMENTS
+
+// keepLocalTime = true means only change the timezone, without
+// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
+// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
+// +0200, so we adjust the time as needed, to be valid.
+//
+// Keeping the time actually adds/subtracts (one hour)
+// from the actual represented time. That is why we call updateOffset
+// a second time. In case it wants us to change the offset again
+// _changeInProgress == true case, then we have to adjust, because
+// there is no such time in the given timezone.
+function getSetOffset (input, keepLocalTime, keepMinutes) {
+ var offset = this._offset || 0,
+ localAdjust;
+ if (!this.isValid()) {
+ return input != null ? this : NaN;
+ }
+ if (input != null) {
+ if (typeof input === 'string') {
+ input = offsetFromString(matchShortOffset, input);
+ if (input === null) {
+ return this;
+ }
+ } else if (Math.abs(input) < 16 && !keepMinutes) {
+ input = input * 60;
+ }
+ if (!this._isUTC && keepLocalTime) {
+ localAdjust = getDateOffset(this);
+ }
+ this._offset = input;
+ this._isUTC = true;
+ if (localAdjust != null) {
+ this.add(localAdjust, 'm');
+ }
+ if (offset !== input) {
+ if (!keepLocalTime || this._changeInProgress) {
+ addSubtract(this, createDuration(input - offset, 'm'), 1, false);
+ } else if (!this._changeInProgress) {
+ this._changeInProgress = true;
+ hooks.updateOffset(this, true);
+ this._changeInProgress = null;
+ }
+ }
+ return this;
+ } else {
+ return this._isUTC ? offset : getDateOffset(this);
+ }
+}
+
+function getSetZone (input, keepLocalTime) {
+ if (input != null) {
+ if (typeof input !== 'string') {
+ input = -input;
+ }
+
+ this.utcOffset(input, keepLocalTime);
+
+ return this;
+ } else {
+ return -this.utcOffset();
+ }
+}
+
+function setOffsetToUTC (keepLocalTime) {
+ return this.utcOffset(0, keepLocalTime);
+}
+
+function setOffsetToLocal (keepLocalTime) {
+ if (this._isUTC) {
+ this.utcOffset(0, keepLocalTime);
+ this._isUTC = false;
+
+ if (keepLocalTime) {
+ this.subtract(getDateOffset(this), 'm');
+ }
+ }
+ return this;
+}
+
+function setOffsetToParsedOffset () {
+ if (this._tzm != null) {
+ this.utcOffset(this._tzm, false, true);
+ } else if (typeof this._i === 'string') {
+ var tZone = offsetFromString(matchOffset, this._i);
+ if (tZone != null) {
+ this.utcOffset(tZone);
+ }
+ else {
+ this.utcOffset(0, true);
+ }
+ }
+ return this;
+}
+
+function hasAlignedHourOffset (input) {
+ if (!this.isValid()) {
+ return false;
+ }
+ input = input ? createLocal(input).utcOffset() : 0;
+
+ return (this.utcOffset() - input) % 60 === 0;
+}
+
+function isDaylightSavingTime () {
+ return (
+ this.utcOffset() > this.clone().month(0).utcOffset() ||
+ this.utcOffset() > this.clone().month(5).utcOffset()
+ );
+}
+
+function isDaylightSavingTimeShifted () {
+ if (!isUndefined(this._isDSTShifted)) {
+ return this._isDSTShifted;
+ }
+
+ var c = {};
+
+ copyConfig(c, this);
+ c = prepareConfig(c);
+
+ if (c._a) {
+ var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
+ this._isDSTShifted = this.isValid() &&
+ compareArrays(c._a, other.toArray()) > 0;
+ } else {
+ this._isDSTShifted = false;
+ }
+
+ return this._isDSTShifted;
+}
+
+function isLocal () {
+ return this.isValid() ? !this._isUTC : false;
+}
+
+function isUtcOffset () {
+ return this.isValid() ? this._isUTC : false;
+}
+
+function isUtc () {
+ return this.isValid() ? this._isUTC && this._offset === 0 : false;
+}
+
+// ASP.NET json date format regex
+var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
+
+// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
+// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
+// and further modified to allow for strings containing both week and day
+var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;
+
+function createDuration (input, key) {
+ var duration = input,
+ // matching against regexp is expensive, do it on demand
+ match = null,
+ sign,
+ ret,
+ diffRes;
+
+ if (isDuration(input)) {
+ duration = {
+ ms : input._milliseconds,
+ d : input._days,
+ M : input._months
+ };
+ } else if (isNumber(input)) {
+ duration = {};
+ if (key) {
+ duration[key] = input;
+ } else {
+ duration.milliseconds = input;
+ }
+ } else if (!!(match = aspNetRegex.exec(input))) {
+ sign = (match[1] === '-') ? -1 : 1;
+ duration = {
+ y : 0,
+ d : toInt(match[DATE]) * sign,
+ h : toInt(match[HOUR]) * sign,
+ m : toInt(match[MINUTE]) * sign,
+ s : toInt(match[SECOND]) * sign,
+ ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
+ };
+ } else if (!!(match = isoRegex.exec(input))) {
+ sign = (match[1] === '-') ? -1 : 1;
+ duration = {
+ y : parseIso(match[2], sign),
+ M : parseIso(match[3], sign),
+ w : parseIso(match[4], sign),
+ d : parseIso(match[5], sign),
+ h : parseIso(match[6], sign),
+ m : parseIso(match[7], sign),
+ s : parseIso(match[8], sign)
+ };
+ } else if (duration == null) {// checks for null or undefined
+ duration = {};
+ } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
+ diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
+
+ duration = {};
+ duration.ms = diffRes.milliseconds;
+ duration.M = diffRes.months;
+ }
+
+ ret = new Duration(duration);
+
+ if (isDuration(input) && hasOwnProp(input, '_locale')) {
+ ret._locale = input._locale;
+ }
+
+ return ret;
+}
+
+createDuration.fn = Duration.prototype;
+createDuration.invalid = createInvalid$1;
+
+function parseIso (inp, sign) {
+ // We'd normally use ~~inp for this, but unfortunately it also
+ // converts floats to ints.
+ // inp may be undefined, so careful calling replace on it.
+ var res = inp && parseFloat(inp.replace(',', '.'));
+ // apply sign while we're at it
+ return (isNaN(res) ? 0 : res) * sign;
+}
+
+function positiveMomentsDifference(base, other) {
+ var res = {milliseconds: 0, months: 0};
+
+ res.months = other.month() - base.month() +
+ (other.year() - base.year()) * 12;
+ if (base.clone().add(res.months, 'M').isAfter(other)) {
+ --res.months;
+ }
+
+ res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
+
+ return res;
+}
+
+function momentsDifference(base, other) {
+ var res;
+ if (!(base.isValid() && other.isValid())) {
+ return {milliseconds: 0, months: 0};
+ }
+
+ other = cloneWithOffset(other, base);
+ if (base.isBefore(other)) {
+ res = positiveMomentsDifference(base, other);
+ } else {
+ res = positiveMomentsDifference(other, base);
+ res.milliseconds = -res.milliseconds;
+ res.months = -res.months;
+ }
+
+ return res;
+}
+
+// TODO: remove 'name' arg after deprecation is removed
+function createAdder(direction, name) {
+ return function (val, period) {
+ var dur, tmp;
+ //invert the arguments, but complain about it
+ if (period !== null && !isNaN(+period)) {
+ deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
+ 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
+ tmp = val; val = period; period = tmp;
+ }
+
+ val = typeof val === 'string' ? +val : val;
+ dur = createDuration(val, period);
+ addSubtract(this, dur, direction);
+ return this;
+ };
+}
+
+function addSubtract (mom, duration, isAdding, updateOffset) {
+ var milliseconds = duration._milliseconds,
+ days = absRound(duration._days),
+ months = absRound(duration._months);
+
+ if (!mom.isValid()) {
+ // No op
+ return;
+ }
+
+ updateOffset = updateOffset == null ? true : updateOffset;
+
+ if (milliseconds) {
+ mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
+ }
+ if (days) {
+ set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
+ }
+ if (months) {
+ setMonth(mom, get(mom, 'Month') + months * isAdding);
+ }
+ if (updateOffset) {
+ hooks.updateOffset(mom, days || months);
+ }
+}
+
+var add = createAdder(1, 'add');
+var subtract = createAdder(-1, 'subtract');
+
+function getCalendarFormat(myMoment, now) {
+ var diff = myMoment.diff(now, 'days', true);
+ return diff < -6 ? 'sameElse' :
+ diff < -1 ? 'lastWeek' :
+ diff < 0 ? 'lastDay' :
+ diff < 1 ? 'sameDay' :
+ diff < 2 ? 'nextDay' :
+ diff < 7 ? 'nextWeek' : 'sameElse';
+}
+
+function calendar$1 (time, formats) {
+ // We want to compare the start of today, vs this.
+ // Getting start-of-today depends on whether we're local/utc/offset or not.
+ var now = time || createLocal(),
+ sod = cloneWithOffset(now, this).startOf('day'),
+ format = hooks.calendarFormat(this, sod) || 'sameElse';
+
+ var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
+
+ return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
+}
+
+function clone () {
+ return new Moment(this);
+}
+
+function isAfter (input, units) {
+ var localInput = isMoment(input) ? input : createLocal(input);
+ if (!(this.isValid() && localInput.isValid())) {
+ return false;
+ }
+ units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+ if (units === 'millisecond') {
+ return this.valueOf() > localInput.valueOf();
+ } else {
+ return localInput.valueOf() < this.clone().startOf(units).valueOf();
+ }
+}
+
+function isBefore (input, units) {
+ var localInput = isMoment(input) ? input : createLocal(input);
+ if (!(this.isValid() && localInput.isValid())) {
+ return false;
+ }
+ units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
+ if (units === 'millisecond') {
+ return this.valueOf() < localInput.valueOf();
+ } else {
+ return this.clone().endOf(units).valueOf() < localInput.valueOf();
+ }
+}
+
+function isBetween (from, to, units, inclusivity) {
+ inclusivity = inclusivity || '()';
+ return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
+ (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
+}
+
+function isSame (input, units) {
+ var localInput = isMoment(input) ? input : createLocal(input),
+ inputMs;
+ if (!(this.isValid() && localInput.isValid())) {
+ return false;
+ }
+ units = normalizeUnits(units || 'millisecond');
+ if (units === 'millisecond') {
+ return this.valueOf() === localInput.valueOf();
+ } else {
+ inputMs = localInput.valueOf();
+ return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
+ }
+}
+
+function isSameOrAfter (input, units) {
+ return this.isSame(input, units) || this.isAfter(input,units);
+}
+
+function isSameOrBefore (input, units) {
+ return this.isSame(input, units) || this.isBefore(input,units);
+}
+
+function diff (input, units, asFloat) {
+ var that,
+ zoneDelta,
+ delta, output;
+
+ if (!this.isValid()) {
+ return NaN;
+ }
+
+ that = cloneWithOffset(input, this);
+
+ if (!that.isValid()) {
+ return NaN;
+ }
+
+ zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
+
+ units = normalizeUnits(units);
+
+ if (units === 'year' || units === 'month' || units === 'quarter') {
+ output = monthDiff(this, that);
+ if (units === 'quarter') {
+ output = output / 3;
+ } else if (units === 'year') {
+ output = output / 12;
+ }
+ } else {
+ delta = this - that;
+ output = units === 'second' ? delta / 1e3 : // 1000
+ units === 'minute' ? delta / 6e4 : // 1000 * 60
+ units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60
+ units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
+ units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
+ delta;
+ }
+ return asFloat ? output : absFloor(output);
+}
+
+function monthDiff (a, b) {
+ // difference in months
+ var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
+ // b is in (anchor - 1 month, anchor + 1 month)
+ anchor = a.clone().add(wholeMonthDiff, 'months'),
+ anchor2, adjust;
+
+ if (b - anchor < 0) {
+ anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
+ // linear across the month
+ adjust = (b - anchor) / (anchor - anchor2);
+ } else {
+ anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
+ // linear across the month
+ adjust = (b - anchor) / (anchor2 - anchor);
+ }
+
+ //check for negative zero, return zero if negative zero
+ return -(wholeMonthDiff + adjust) || 0;
+}
+
+hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
+hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
+
+function toString () {
+ return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
+}
+
+function toISOString() {
+ if (!this.isValid()) {
+ return null;
+ }
+ var m = this.clone().utc();
+ if (m.year() < 0 || m.year() > 9999) {
+ return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+ }
+ if (isFunction(Date.prototype.toISOString)) {
+ // native implementation is ~50x faster, use it when we can
+ return this.toDate().toISOString();
+ }
+ return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+}
+
+/**
+ * Return a human readable representation of a moment that can
+ * also be evaluated to get a new moment which is the same
+ *
+ * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
+ */
+function inspect () {
+ if (!this.isValid()) {
+ return 'moment.invalid(/* ' + this._i + ' */)';
+ }
+ var func = 'moment';
+ var zone = '';
+ if (!this.isLocal()) {
+ func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
+ zone = 'Z';
+ }
+ var prefix = '[' + func + '("]';
+ var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
+ var datetime = '-MM-DD[T]HH:mm:ss.SSS';
+ var suffix = zone + '[")]';
+
+ return this.format(prefix + year + datetime + suffix);
+}
+
+function format (inputString) {
+ if (!inputString) {
+ inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
+ }
+ var output = formatMoment(this, inputString);
+ return this.localeData().postformat(output);
+}
+
+function from (time, withoutSuffix) {
+ if (this.isValid() &&
+ ((isMoment(time) && time.isValid()) ||
+ createLocal(time).isValid())) {
+ return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
+ } else {
+ return this.localeData().invalidDate();
+ }
+}
+
+function fromNow (withoutSuffix) {
+ return this.from(createLocal(), withoutSuffix);
+}
+
+function to (time, withoutSuffix) {
+ if (this.isValid() &&
+ ((isMoment(time) && time.isValid()) ||
+ createLocal(time).isValid())) {
+ return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
+ } else {
+ return this.localeData().invalidDate();
+ }
+}
+
+function toNow (withoutSuffix) {
+ return this.to(createLocal(), withoutSuffix);
+}
+
+// If passed a locale key, it will set the locale for this
+// instance. Otherwise, it will return the locale configuration
+// variables for this instance.
+function locale (key) {
+ var newLocaleData;
+
+ if (key === undefined) {
+ return this._locale._abbr;
+ } else {
+ newLocaleData = getLocale(key);
+ if (newLocaleData != null) {
+ this._locale = newLocaleData;
+ }
+ return this;
+ }
+}
+
+var lang = deprecate(
+ 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
+ function (key) {
+ if (key === undefined) {
+ return this.localeData();
+ } else {
+ return this.locale(key);
+ }
+ }
+);
+
+function localeData () {
+ return this._locale;
+}
+
+function startOf (units) {
+ units = normalizeUnits(units);
+ // the following switch intentionally omits break keywords
+ // to utilize falling through the cases.
+ switch (units) {
+ case 'year':
+ this.month(0);
+ /* falls through */
+ case 'quarter':
+ case 'month':
+ this.date(1);
+ /* falls through */
+ case 'week':
+ case 'isoWeek':
+ case 'day':
+ case 'date':
+ this.hours(0);
+ /* falls through */
+ case 'hour':
+ this.minutes(0);
+ /* falls through */
+ case 'minute':
+ this.seconds(0);
+ /* falls through */
+ case 'second':
+ this.milliseconds(0);
+ }
+
+ // weeks are a special case
+ if (units === 'week') {
+ this.weekday(0);
+ }
+ if (units === 'isoWeek') {
+ this.isoWeekday(1);
+ }
+
+ // quarters are also special
+ if (units === 'quarter') {
+ this.month(Math.floor(this.month() / 3) * 3);
+ }
+
+ return this;
+}
+
+function endOf (units) {
+ units = normalizeUnits(units);
+ if (units === undefined || units === 'millisecond') {
+ return this;
+ }
+
+ // 'date' is an alias for 'day', so it should be considered as such.
+ if (units === 'date') {
+ units = 'day';
+ }
+
+ return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
+}
+
+function valueOf () {
+ return this._d.valueOf() - ((this._offset || 0) * 60000);
+}
+
+function unix () {
+ return Math.floor(this.valueOf() / 1000);
+}
+
+function toDate () {
+ return new Date(this.valueOf());
+}
+
+function toArray () {
+ var m = this;
+ return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
+}
+
+function toObject () {
+ var m = this;
+ return {
+ years: m.year(),
+ months: m.month(),
+ date: m.date(),
+ hours: m.hours(),
+ minutes: m.minutes(),
+ seconds: m.seconds(),
+ milliseconds: m.milliseconds()
+ };
+}
+
+function toJSON () {
+ // new Date(NaN).toJSON() === null
+ return this.isValid() ? this.toISOString() : null;
+}
+
+function isValid$2 () {
+ return isValid(this);
+}
+
+function parsingFlags () {
+ return extend({}, getParsingFlags(this));
+}
+
+function invalidAt () {
+ return getParsingFlags(this).overflow;
+}
+
+function creationData() {
+ return {
+ input: this._i,
+ format: this._f,
+ locale: this._locale,
+ isUTC: this._isUTC,
+ strict: this._strict
+ };
+}
+
+// FORMATTING
+
+addFormatToken(0, ['gg', 2], 0, function () {
+ return this.weekYear() % 100;
+});
+
+addFormatToken(0, ['GG', 2], 0, function () {
+ return this.isoWeekYear() % 100;
+});
+
+function addWeekYearFormatToken (token, getter) {
+ addFormatToken(0, [token, token.length], 0, getter);
+}
+
+addWeekYearFormatToken('gggg', 'weekYear');
+addWeekYearFormatToken('ggggg', 'weekYear');
+addWeekYearFormatToken('GGGG', 'isoWeekYear');
+addWeekYearFormatToken('GGGGG', 'isoWeekYear');
+
+// ALIASES
+
+addUnitAlias('weekYear', 'gg');
+addUnitAlias('isoWeekYear', 'GG');
+
+// PRIORITY
+
+addUnitPriority('weekYear', 1);
+addUnitPriority('isoWeekYear', 1);
+
+
+// PARSING
+
+addRegexToken('G', matchSigned);
+addRegexToken('g', matchSigned);
+addRegexToken('GG', match1to2, match2);
+addRegexToken('gg', match1to2, match2);
+addRegexToken('GGGG', match1to4, match4);
+addRegexToken('gggg', match1to4, match4);
+addRegexToken('GGGGG', match1to6, match6);
+addRegexToken('ggggg', match1to6, match6);
+
+addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
+ week[token.substr(0, 2)] = toInt(input);
+});
+
+addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
+ week[token] = hooks.parseTwoDigitYear(input);
+});
+
+// MOMENTS
+
+function getSetWeekYear (input) {
+ return getSetWeekYearHelper.call(this,
+ input,
+ this.week(),
+ this.weekday(),
+ this.localeData()._week.dow,
+ this.localeData()._week.doy);
+}
+
+function getSetISOWeekYear (input) {
+ return getSetWeekYearHelper.call(this,
+ input, this.isoWeek(), this.isoWeekday(), 1, 4);
+}
+
+function getISOWeeksInYear () {
+ return weeksInYear(this.year(), 1, 4);
+}
+
+function getWeeksInYear () {
+ var weekInfo = this.localeData()._week;
+ return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
+}
+
+function getSetWeekYearHelper(input, week, weekday, dow, doy) {
+ var weeksTarget;
+ if (input == null) {
+ return weekOfYear(this, dow, doy).year;
+ } else {
+ weeksTarget = weeksInYear(input, dow, doy);
+ if (week > weeksTarget) {
+ week = weeksTarget;
+ }
+ return setWeekAll.call(this, input, week, weekday, dow, doy);
+ }
+}
+
+function setWeekAll(weekYear, week, weekday, dow, doy) {
+ var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
+ date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
+
+ this.year(date.getUTCFullYear());
+ this.month(date.getUTCMonth());
+ this.date(date.getUTCDate());
+ return this;
+}
+
+// FORMATTING
+
+addFormatToken('Q', 0, 'Qo', 'quarter');
+
+// ALIASES
+
+addUnitAlias('quarter', 'Q');
+
+// PRIORITY
+
+addUnitPriority('quarter', 7);
+
+// PARSING
+
+addRegexToken('Q', match1);
+addParseToken('Q', function (input, array) {
+ array[MONTH] = (toInt(input) - 1) * 3;
+});
+
+// MOMENTS
+
+function getSetQuarter (input) {
+ return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
+}
+
+// FORMATTING
+
+addFormatToken('D', ['DD', 2], 'Do', 'date');
+
+// ALIASES
+
+addUnitAlias('date', 'D');
+
+// PRIOROITY
+addUnitPriority('date', 9);
+
+// PARSING
+
+addRegexToken('D', match1to2);
+addRegexToken('DD', match1to2, match2);
+addRegexToken('Do', function (isStrict, locale) {
+ // TODO: Remove "ordinalParse" fallback in next major release.
+ return isStrict ?
+ (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
+ locale._dayOfMonthOrdinalParseLenient;
+});
+
+addParseToken(['D', 'DD'], DATE);
+addParseToken('Do', function (input, array) {
+ array[DATE] = toInt(input.match(match1to2)[0], 10);
+});
+
+// MOMENTS
+
+var getSetDayOfMonth = makeGetSet('Date', true);
+
+// FORMATTING
+
+addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
+
+// ALIASES
+
+addUnitAlias('dayOfYear', 'DDD');
+
+// PRIORITY
+addUnitPriority('dayOfYear', 4);
+
+// PARSING
+
+addRegexToken('DDD', match1to3);
+addRegexToken('DDDD', match3);
+addParseToken(['DDD', 'DDDD'], function (input, array, config) {
+ config._dayOfYear = toInt(input);
+});
+
+// HELPERS
+
+// MOMENTS
+
+function getSetDayOfYear (input) {
+ var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
+ return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
+}
+
+// FORMATTING
+
+addFormatToken('m', ['mm', 2], 0, 'minute');
+
+// ALIASES
+
+addUnitAlias('minute', 'm');
+
+// PRIORITY
+
+addUnitPriority('minute', 14);
+
+// PARSING
+
+addRegexToken('m', match1to2);
+addRegexToken('mm', match1to2, match2);
+addParseToken(['m', 'mm'], MINUTE);
+
+// MOMENTS
+
+var getSetMinute = makeGetSet('Minutes', false);
+
+// FORMATTING
+
+addFormatToken('s', ['ss', 2], 0, 'second');
+
+// ALIASES
+
+addUnitAlias('second', 's');
+
+// PRIORITY
+
+addUnitPriority('second', 15);
+
+// PARSING
+
+addRegexToken('s', match1to2);
+addRegexToken('ss', match1to2, match2);
+addParseToken(['s', 'ss'], SECOND);
+
+// MOMENTS
+
+var getSetSecond = makeGetSet('Seconds', false);
+
+// FORMATTING
+
+addFormatToken('S', 0, 0, function () {
+ return ~~(this.millisecond() / 100);
+});
+
+addFormatToken(0, ['SS', 2], 0, function () {
+ return ~~(this.millisecond() / 10);
+});
+
+addFormatToken(0, ['SSS', 3], 0, 'millisecond');
+addFormatToken(0, ['SSSS', 4], 0, function () {
+ return this.millisecond() * 10;
+});
+addFormatToken(0, ['SSSSS', 5], 0, function () {
+ return this.millisecond() * 100;
+});
+addFormatToken(0, ['SSSSSS', 6], 0, function () {
+ return this.millisecond() * 1000;
+});
+addFormatToken(0, ['SSSSSSS', 7], 0, function () {
+ return this.millisecond() * 10000;
+});
+addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
+ return this.millisecond() * 100000;
+});
+addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
+ return this.millisecond() * 1000000;
+});
+
+
+// ALIASES
+
+addUnitAlias('millisecond', 'ms');
+
+// PRIORITY
+
+addUnitPriority('millisecond', 16);
+
+// PARSING
+
+addRegexToken('S', match1to3, match1);
+addRegexToken('SS', match1to3, match2);
+addRegexToken('SSS', match1to3, match3);
+
+var token;
+for (token = 'SSSS'; token.length <= 9; token += 'S') {
+ addRegexToken(token, matchUnsigned);
+}
+
+function parseMs(input, array) {
+ array[MILLISECOND] = toInt(('0.' + input) * 1000);
+}
+
+for (token = 'S'; token.length <= 9; token += 'S') {
+ addParseToken(token, parseMs);
+}
+// MOMENTS
+
+var getSetMillisecond = makeGetSet('Milliseconds', false);
+
+// FORMATTING
+
+addFormatToken('z', 0, 0, 'zoneAbbr');
+addFormatToken('zz', 0, 0, 'zoneName');
+
+// MOMENTS
+
+function getZoneAbbr () {
+ return this._isUTC ? 'UTC' : '';
+}
+
+function getZoneName () {
+ return this._isUTC ? 'Coordinated Universal Time' : '';
+}
+
+var proto = Moment.prototype;
+
+proto.add = add;
+proto.calendar = calendar$1;
+proto.clone = clone;
+proto.diff = diff;
+proto.endOf = endOf;
+proto.format = format;
+proto.from = from;
+proto.fromNow = fromNow;
+proto.to = to;
+proto.toNow = toNow;
+proto.get = stringGet;
+proto.invalidAt = invalidAt;
+proto.isAfter = isAfter;
+proto.isBefore = isBefore;
+proto.isBetween = isBetween;
+proto.isSame = isSame;
+proto.isSameOrAfter = isSameOrAfter;
+proto.isSameOrBefore = isSameOrBefore;
+proto.isValid = isValid$2;
+proto.lang = lang;
+proto.locale = locale;
+proto.localeData = localeData;
+proto.max = prototypeMax;
+proto.min = prototypeMin;
+proto.parsingFlags = parsingFlags;
+proto.set = stringSet;
+proto.startOf = startOf;
+proto.subtract = subtract;
+proto.toArray = toArray;
+proto.toObject = toObject;
+proto.toDate = toDate;
+proto.toISOString = toISOString;
+proto.inspect = inspect;
+proto.toJSON = toJSON;
+proto.toString = toString;
+proto.unix = unix;
+proto.valueOf = valueOf;
+proto.creationData = creationData;
+
+// Year
+proto.year = getSetYear;
+proto.isLeapYear = getIsLeapYear;
+
+// Week Year
+proto.weekYear = getSetWeekYear;
+proto.isoWeekYear = getSetISOWeekYear;
+
+// Quarter
+proto.quarter = proto.quarters = getSetQuarter;
+
+// Month
+proto.month = getSetMonth;
+proto.daysInMonth = getDaysInMonth;
+
+// Week
+proto.week = proto.weeks = getSetWeek;
+proto.isoWeek = proto.isoWeeks = getSetISOWeek;
+proto.weeksInYear = getWeeksInYear;
+proto.isoWeeksInYear = getISOWeeksInYear;
+
+// Day
+proto.date = getSetDayOfMonth;
+proto.day = proto.days = getSetDayOfWeek;
+proto.weekday = getSetLocaleDayOfWeek;
+proto.isoWeekday = getSetISODayOfWeek;
+proto.dayOfYear = getSetDayOfYear;
+
+// Hour
+proto.hour = proto.hours = getSetHour;
+
+// Minute
+proto.minute = proto.minutes = getSetMinute;
+
+// Second
+proto.second = proto.seconds = getSetSecond;
+
+// Millisecond
+proto.millisecond = proto.milliseconds = getSetMillisecond;
+
+// Offset
+proto.utcOffset = getSetOffset;
+proto.utc = setOffsetToUTC;
+proto.local = setOffsetToLocal;
+proto.parseZone = setOffsetToParsedOffset;
+proto.hasAlignedHourOffset = hasAlignedHourOffset;
+proto.isDST = isDaylightSavingTime;
+proto.isLocal = isLocal;
+proto.isUtcOffset = isUtcOffset;
+proto.isUtc = isUtc;
+proto.isUTC = isUtc;
+
+// Timezone
+proto.zoneAbbr = getZoneAbbr;
+proto.zoneName = getZoneName;
+
+// Deprecations
+proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
+proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
+proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
+proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
+proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
+
+function createUnix (input) {
+ return createLocal(input * 1000);
+}
+
+function createInZone () {
+ return createLocal.apply(null, arguments).parseZone();
+}
+
+function preParsePostFormat (string) {
+ return string;
+}
+
+var proto$1 = Locale.prototype;
+
+proto$1.calendar = calendar;
+proto$1.longDateFormat = longDateFormat;
+proto$1.invalidDate = invalidDate;
+proto$1.ordinal = ordinal;
+proto$1.preparse = preParsePostFormat;
+proto$1.postformat = preParsePostFormat;
+proto$1.relativeTime = relativeTime;
+proto$1.pastFuture = pastFuture;
+proto$1.set = set;
+
+// Month
+proto$1.months = localeMonths;
+proto$1.monthsShort = localeMonthsShort;
+proto$1.monthsParse = localeMonthsParse;
+proto$1.monthsRegex = monthsRegex;
+proto$1.monthsShortRegex = monthsShortRegex;
+
+// Week
+proto$1.week = localeWeek;
+proto$1.firstDayOfYear = localeFirstDayOfYear;
+proto$1.firstDayOfWeek = localeFirstDayOfWeek;
+
+// Day of Week
+proto$1.weekdays = localeWeekdays;
+proto$1.weekdaysMin = localeWeekdaysMin;
+proto$1.weekdaysShort = localeWeekdaysShort;
+proto$1.weekdaysParse = localeWeekdaysParse;
+
+proto$1.weekdaysRegex = weekdaysRegex;
+proto$1.weekdaysShortRegex = weekdaysShortRegex;
+proto$1.weekdaysMinRegex = weekdaysMinRegex;
+
+// Hours
+proto$1.isPM = localeIsPM;
+proto$1.meridiem = localeMeridiem;
+
+function get$1 (format, index, field, setter) {
+ var locale = getLocale();
+ var utc = createUTC().set(setter, index);
+ return locale[field](utc, format);
+}
+
+function listMonthsImpl (format, index, field) {
+ if (isNumber(format)) {
+ index = format;
+ format = undefined;
+ }
+
+ format = format || '';
+
+ if (index != null) {
+ return get$1(format, index, field, 'month');
+ }
+
+ var i;
+ var out = [];
+ for (i = 0; i < 12; i++) {
+ out[i] = get$1(format, i, field, 'month');
+ }
+ return out;
+}
+
+// ()
+// (5)
+// (fmt, 5)
+// (fmt)
+// (true)
+// (true, 5)
+// (true, fmt, 5)
+// (true, fmt)
+function listWeekdaysImpl (localeSorted, format, index, field) {
+ if (typeof localeSorted === 'boolean') {
+ if (isNumber(format)) {
+ index = format;
+ format = undefined;
+ }
+
+ format = format || '';
+ } else {
+ format = localeSorted;
+ index = format;
+ localeSorted = false;
+
+ if (isNumber(format)) {
+ index = format;
+ format = undefined;
+ }
+
+ format = format || '';
+ }
+
+ var locale = getLocale(),
+ shift = localeSorted ? locale._week.dow : 0;
+
+ if (index != null) {
+ return get$1(format, (index + shift) % 7, field, 'day');
+ }
+
+ var i;
+ var out = [];
+ for (i = 0; i < 7; i++) {
+ out[i] = get$1(format, (i + shift) % 7, field, 'day');
+ }
+ return out;
+}
+
+function listMonths (format, index) {
+ return listMonthsImpl(format, index, 'months');
+}
+
+function listMonthsShort (format, index) {
+ return listMonthsImpl(format, index, 'monthsShort');
+}
+
+function listWeekdays (localeSorted, format, index) {
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
+}
+
+function listWeekdaysShort (localeSorted, format, index) {
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
+}
+
+function listWeekdaysMin (localeSorted, format, index) {
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
+}
+
+getSetGlobalLocale('en', {
+ dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
+ ordinal : function (number) {
+ var b = number % 10,
+ output = (toInt(number % 100 / 10) === 1) ? 'th' :
+ (b === 1) ? 'st' :
+ (b === 2) ? 'nd' :
+ (b === 3) ? 'rd' : 'th';
+ return number + output;
+ }
+});
+
+// Side effect imports
+hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
+hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
+
+var mathAbs = Math.abs;
+
+function abs () {
+ var data = this._data;
+
+ this._milliseconds = mathAbs(this._milliseconds);
+ this._days = mathAbs(this._days);
+ this._months = mathAbs(this._months);
+
+ data.milliseconds = mathAbs(data.milliseconds);
+ data.seconds = mathAbs(data.seconds);
+ data.minutes = mathAbs(data.minutes);
+ data.hours = mathAbs(data.hours);
+ data.months = mathAbs(data.months);
+ data.years = mathAbs(data.years);
+
+ return this;
+}
+
+function addSubtract$1 (duration, input, value, direction) {
+ var other = createDuration(input, value);
+
+ duration._milliseconds += direction * other._milliseconds;
+ duration._days += direction * other._days;
+ duration._months += direction * other._months;
+
+ return duration._bubble();
+}
+
+// supports only 2.0-style add(1, 's') or add(duration)
+function add$1 (input, value) {
+ return addSubtract$1(this, input, value, 1);
+}
+
+// supports only 2.0-style subtract(1, 's') or subtract(duration)
+function subtract$1 (input, value) {
+ return addSubtract$1(this, input, value, -1);
+}
+
+function absCeil (number) {
+ if (number < 0) {
+ return Math.floor(number);
+ } else {
+ return Math.ceil(number);
+ }
+}
+
+function bubble () {
+ var milliseconds = this._milliseconds;
+ var days = this._days;
+ var months = this._months;
+ var data = this._data;
+ var seconds, minutes, hours, years, monthsFromDays;
+
+ // if we have a mix of positive and negative values, bubble down first
+ // check: https://github.com/moment/moment/issues/2166
+ if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
+ (milliseconds <= 0 && days <= 0 && months <= 0))) {
+ milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
+ days = 0;
+ months = 0;
+ }
+
+ // The following code bubbles up values, see the tests for
+ // examples of what that means.
+ data.milliseconds = milliseconds % 1000;
+
+ seconds = absFloor(milliseconds / 1000);
+ data.seconds = seconds % 60;
+
+ minutes = absFloor(seconds / 60);
+ data.minutes = minutes % 60;
+
+ hours = absFloor(minutes / 60);
+ data.hours = hours % 24;
+
+ days += absFloor(hours / 24);
+
+ // convert days to months
+ monthsFromDays = absFloor(daysToMonths(days));
+ months += monthsFromDays;
+ days -= absCeil(monthsToDays(monthsFromDays));
+
+ // 12 months -> 1 year
+ years = absFloor(months / 12);
+ months %= 12;
+
+ data.days = days;
+ data.months = months;
+ data.years = years;
+
+ return this;
+}
+
+function daysToMonths (days) {
+ // 400 years have 146097 days (taking into account leap year rules)
+ // 400 years have 12 months === 4800
+ return days * 4800 / 146097;
+}
+
+function monthsToDays (months) {
+ // the reverse of daysToMonths
+ return months * 146097 / 4800;
+}
+
+function as (units) {
+ if (!this.isValid()) {
+ return NaN;
+ }
+ var days;
+ var months;
+ var milliseconds = this._milliseconds;
+
+ units = normalizeUnits(units);
+
+ if (units === 'month' || units === 'year') {
+ days = this._days + milliseconds / 864e5;
+ months = this._months + daysToMonths(days);
+ return units === 'month' ? months : months / 12;
+ } else {
+ // handle milliseconds separately because of floating point math errors (issue #1867)
+ days = this._days + Math.round(monthsToDays(this._months));
+ switch (units) {
+ case 'week' : return days / 7 + milliseconds / 6048e5;
+ case 'day' : return days + milliseconds / 864e5;
+ case 'hour' : return days * 24 + milliseconds / 36e5;
+ case 'minute' : return days * 1440 + milliseconds / 6e4;
+ case 'second' : return days * 86400 + milliseconds / 1000;
+ // Math.floor prevents floating point math errors here
+ case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
+ default: throw new Error('Unknown unit ' + units);
+ }
+ }
+}
+
+// TODO: Use this.as('ms')?
+function valueOf$1 () {
+ if (!this.isValid()) {
+ return NaN;
+ }
+ return (
+ this._milliseconds +
+ this._days * 864e5 +
+ (this._months % 12) * 2592e6 +
+ toInt(this._months / 12) * 31536e6
+ );
+}
+
+function makeAs (alias) {
+ return function () {
+ return this.as(alias);
+ };
+}
+
+var asMilliseconds = makeAs('ms');
+var asSeconds = makeAs('s');
+var asMinutes = makeAs('m');
+var asHours = makeAs('h');
+var asDays = makeAs('d');
+var asWeeks = makeAs('w');
+var asMonths = makeAs('M');
+var asYears = makeAs('y');
+
+function get$2 (units) {
+ units = normalizeUnits(units);
+ return this.isValid() ? this[units + 's']() : NaN;
+}
+
+function makeGetter(name) {
+ return function () {
+ return this.isValid() ? this._data[name] : NaN;
+ };
+}
+
+var milliseconds = makeGetter('milliseconds');
+var seconds = makeGetter('seconds');
+var minutes = makeGetter('minutes');
+var hours = makeGetter('hours');
+var days = makeGetter('days');
+var months = makeGetter('months');
+var years = makeGetter('years');
+
+function weeks () {
+ return absFloor(this.days() / 7);
+}
+
+var round = Math.round;
+var thresholds = {
+ ss: 44, // a few seconds to seconds
+ s : 45, // seconds to minute
+ m : 45, // minutes to hour
+ h : 22, // hours to day
+ d : 26, // days to month
+ M : 11 // months to year
+};
+
+// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
+function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
+ return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
+}
+
+function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
+ var duration = createDuration(posNegDuration).abs();
+ var seconds = round(duration.as('s'));
+ var minutes = round(duration.as('m'));
+ var hours = round(duration.as('h'));
+ var days = round(duration.as('d'));
+ var months = round(duration.as('M'));
+ var years = round(duration.as('y'));
+
+ var a = seconds <= thresholds.ss && ['s', seconds] ||
+ seconds < thresholds.s && ['ss', seconds] ||
+ minutes <= 1 && ['m'] ||
+ minutes < thresholds.m && ['mm', minutes] ||
+ hours <= 1 && ['h'] ||
+ hours < thresholds.h && ['hh', hours] ||
+ days <= 1 && ['d'] ||
+ days < thresholds.d && ['dd', days] ||
+ months <= 1 && ['M'] ||
+ months < thresholds.M && ['MM', months] ||
+ years <= 1 && ['y'] || ['yy', years];
+
+ a[2] = withoutSuffix;
+ a[3] = +posNegDuration > 0;
+ a[4] = locale;
+ return substituteTimeAgo.apply(null, a);
+}
+
+// This function allows you to set the rounding function for relative time strings
+function getSetRelativeTimeRounding (roundingFunction) {
+ if (roundingFunction === undefined) {
+ return round;
+ }
+ if (typeof(roundingFunction) === 'function') {
+ round = roundingFunction;
+ return true;
+ }
+ return false;
+}
+
+// This function allows you to set a threshold for relative time strings
+function getSetRelativeTimeThreshold (threshold, limit) {
+ if (thresholds[threshold] === undefined) {
+ return false;
+ }
+ if (limit === undefined) {
+ return thresholds[threshold];
+ }
+ thresholds[threshold] = limit;
+ if (threshold === 's') {
+ thresholds.ss = limit - 1;
+ }
+ return true;
+}
+
+function humanize (withSuffix) {
+ if (!this.isValid()) {
+ return this.localeData().invalidDate();
+ }
+
+ var locale = this.localeData();
+ var output = relativeTime$1(this, !withSuffix, locale);
+
+ if (withSuffix) {
+ output = locale.pastFuture(+this, output);
+ }
+
+ return locale.postformat(output);
+}
+
+var abs$1 = Math.abs;
+
+function toISOString$1() {
+ // for ISO strings we do not use the normal bubbling rules:
+ // * milliseconds bubble up until they become hours
+ // * days do not bubble at all
+ // * months bubble up until they become years
+ // This is because there is no context-free conversion between hours and days
+ // (think of clock changes)
+ // and also not between days and months (28-31 days per month)
+ if (!this.isValid()) {
+ return this.localeData().invalidDate();
+ }
+
+ var seconds = abs$1(this._milliseconds) / 1000;
+ var days = abs$1(this._days);
+ var months = abs$1(this._months);
+ var minutes, hours, years;
+
+ // 3600 seconds -> 60 minutes -> 1 hour
+ minutes = absFloor(seconds / 60);
+ hours = absFloor(minutes / 60);
+ seconds %= 60;
+ minutes %= 60;
+
+ // 12 months -> 1 year
+ years = absFloor(months / 12);
+ months %= 12;
+
+
+ // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
+ var Y = years;
+ var M = months;
+ var D = days;
+ var h = hours;
+ var m = minutes;
+ var s = seconds;
+ var total = this.asSeconds();
+
+ if (!total) {
+ // this is the same as C#'s (Noda) and python (isodate)...
+ // but not other JS (goog.date)
+ return 'P0D';
+ }
+
+ return (total < 0 ? '-' : '') +
+ 'P' +
+ (Y ? Y + 'Y' : '') +
+ (M ? M + 'M' : '') +
+ (D ? D + 'D' : '') +
+ ((h || m || s) ? 'T' : '') +
+ (h ? h + 'H' : '') +
+ (m ? m + 'M' : '') +
+ (s ? s + 'S' : '');
+}
+
+var proto$2 = Duration.prototype;
+
+proto$2.isValid = isValid$1;
+proto$2.abs = abs;
+proto$2.add = add$1;
+proto$2.subtract = subtract$1;
+proto$2.as = as;
+proto$2.asMilliseconds = asMilliseconds;
+proto$2.asSeconds = asSeconds;
+proto$2.asMinutes = asMinutes;
+proto$2.asHours = asHours;
+proto$2.asDays = asDays;
+proto$2.asWeeks = asWeeks;
+proto$2.asMonths = asMonths;
+proto$2.asYears = asYears;
+proto$2.valueOf = valueOf$1;
+proto$2._bubble = bubble;
+proto$2.get = get$2;
+proto$2.milliseconds = milliseconds;
+proto$2.seconds = seconds;
+proto$2.minutes = minutes;
+proto$2.hours = hours;
+proto$2.days = days;
+proto$2.weeks = weeks;
+proto$2.months = months;
+proto$2.years = years;
+proto$2.humanize = humanize;
+proto$2.toISOString = toISOString$1;
+proto$2.toString = toISOString$1;
+proto$2.toJSON = toISOString$1;
+proto$2.locale = locale;
+proto$2.localeData = localeData;
+
+// Deprecations
+proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
+proto$2.lang = lang;
+
+// Side effect imports
+
+// FORMATTING
+
+addFormatToken('X', 0, 0, 'unix');
+addFormatToken('x', 0, 0, 'valueOf');
+
+// PARSING
+
+addRegexToken('x', matchSigned);
+addRegexToken('X', matchTimestamp);
+addParseToken('X', function (input, array, config) {
+ config._d = new Date(parseFloat(input, 10) * 1000);
+});
+addParseToken('x', function (input, array, config) {
+ config._d = new Date(toInt(input));
+});
+
+// Side effect imports
+
+
+hooks.version = '2.18.1';
+
+setHookCallback(createLocal);
+
+hooks.fn = proto;
+hooks.min = min;
+hooks.max = max;
+hooks.now = now;
+hooks.utc = createUTC;
+hooks.unix = createUnix;
+hooks.months = listMonths;
+hooks.isDate = isDate;
+hooks.locale = getSetGlobalLocale;
+hooks.invalid = createInvalid;
+hooks.duration = createDuration;
+hooks.isMoment = isMoment;
+hooks.weekdays = listWeekdays;
+hooks.parseZone = createInZone;
+hooks.localeData = getLocale;
+hooks.isDuration = isDuration;
+hooks.monthsShort = listMonthsShort;
+hooks.weekdaysMin = listWeekdaysMin;
+hooks.defineLocale = defineLocale;
+hooks.updateLocale = updateLocale;
+hooks.locales = listLocales;
+hooks.weekdaysShort = listWeekdaysShort;
+hooks.normalizeUnits = normalizeUnits;
+hooks.relativeTimeRounding = getSetRelativeTimeRounding;
+hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
+hooks.calendarFormat = getCalendarFormat;
+hooks.prototype = proto;
+
+return hooks;
+
+})));
+
+},{}],7:[function(require,module,exports){
+/**
+ * @namespace Chart
+ */
+var Chart = require(28)();
+
+require(26)(Chart);
+require(40)(Chart);
+require(22)(Chart);
+require(25)(Chart);
+require(30)(Chart);
+require(21)(Chart);
+require(23)(Chart);
+require(24)(Chart);
+require(29)(Chart);
+require(32)(Chart);
+require(33)(Chart);
+require(31)(Chart);
+require(27)(Chart);
+require(34)(Chart);
+
+require(35)(Chart);
+require(36)(Chart);
+require(37)(Chart);
+require(38)(Chart);
+
+require(46)(Chart);
+require(44)(Chart);
+require(45)(Chart);
+require(47)(Chart);
+require(48)(Chart);
+require(49)(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);
+
+// Loading built-it plugins
+var plugins = [];
+
+plugins.push(
+ require(41)(Chart),
+ require(42)(Chart),
+ require(43)(Chart)
+);
+
+Chart.plugins.register(plugins);
+
+module.exports = Chart;
+if (typeof window !== 'undefined') {
+ window.Chart = 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,"40":40,"41":41,"42":42,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"49":49,"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() {
+ var me = this;
+ var meta;
+
+ Chart.DatasetController.prototype.initialize.apply(me, arguments);
+
+ meta = me.getMeta();
+ meta.stack = me.getDataset().stack;
+ meta.bar = true;
+ },
+
+ update: function(reset) {
+ var me = this;
+ var elements = me.getMeta().data;
+ var i, ilen;
+
+ me._ruler = me.getRuler();
+
+ for (i = 0, ilen = elements.length; i < ilen; ++i) {
+ me.updateElement(elements[i], i, reset);
+ }
+ },
+
+ updateElement: function(rectangle, index, reset) {
+ var me = this;
+ var chart = me.chart;
+ var meta = me.getMeta();
+ var dataset = me.getDataset();
+ var custom = rectangle.custom || {};
+ var rectangleOptions = chart.options.elements.rectangle;
+
+ rectangle._xScale = me.getScaleForId(meta.xAxisID);
+ rectangle._yScale = me.getScaleForId(meta.yAxisID);
+ rectangle._datasetIndex = me.index;
+ rectangle._index = index;
+
+ rectangle._model = {
+ datasetLabel: dataset.label,
+ label: chart.data.labels[index],
+ borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
+ backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
+ borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
+ borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
+ };
+
+ me.updateElementGeometry(rectangle, index, reset);
+
+ rectangle.pivot();
+ },
+
+ /**
+ * @private
+ */
+ updateElementGeometry: function(rectangle, index, reset) {
+ var me = this;
+ var model = rectangle._model;
+ var vscale = me.getValueScale();
+ var base = vscale.getBasePixel();
+ var horizontal = vscale.isHorizontal();
+ var ruler = me._ruler || me.getRuler();
+ var vpixels = me.calculateBarValuePixels(me.index, index);
+ var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
+
+ model.horizontal = horizontal;
+ model.base = reset? base : vpixels.base;
+ model.x = horizontal? reset? base : vpixels.head : ipixels.center;
+ model.y = horizontal? ipixels.center : reset? base : vpixels.head;
+ model.height = horizontal? ipixels.size : undefined;
+ model.width = horizontal? undefined : ipixels.size;
+ },
+
+ /**
+ * @private
+ */
+ getValueScaleId: function() {
+ return this.getMeta().yAxisID;
+ },
+
+ /**
+ * @private
+ */
+ getIndexScaleId: function() {
+ return this.getMeta().xAxisID;
+ },
+
+ /**
+ * @private
+ */
+ getValueScale: function() {
+ return this.getScaleForId(this.getValueScaleId());
+ },
+
+ /**
+ * @private
+ */
+ getIndexScale: function() {
+ return this.getScaleForId(this.getIndexScaleId());
+ },
+
+ /**
+ * Returns the effective number of stacks based on groups and bar visibility.
+ * @private
+ */
+ getStackCount: function(last) {
+ var me = this;
+ var chart = me.chart;
+ var scale = me.getIndexScale();
+ var stacked = scale.options.stacked;
+ var ilen = last === undefined? chart.data.datasets.length : last + 1;
+ var stacks = [];
+ var i, meta;
+
+ for (i = 0; i < ilen; ++i) {
+ meta = chart.getDatasetMeta(i);
+ if (meta.bar && chart.isDatasetVisible(i) &&
+ (stacked === false ||
+ (stacked === true && stacks.indexOf(meta.stack) === -1) ||
+ (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
+ stacks.push(meta.stack);
+ }
+ }
+
+ return stacks.length;
+ },
+
+ /**
+ * Returns the stack index for the given dataset based on groups and bar visibility.
+ * @private
+ */
+ getStackIndex: function(datasetIndex) {
+ return this.getStackCount(datasetIndex) - 1;
+ },
+
+ /**
+ * @private
+ */
+ getRuler: function() {
+ var me = this;
+ var scale = me.getIndexScale();
+ var options = scale.options;
+ var stackCount = me.getStackCount();
+ var fullSize = scale.isHorizontal()? scale.width : scale.height;
+ var tickSize = fullSize / scale.ticks.length;
+ var categorySize = tickSize * options.categoryPercentage;
+ var fullBarSize = categorySize / stackCount;
+ var barSize = fullBarSize * options.barPercentage;
+
+ barSize = Math.min(
+ helpers.getValueOrDefault(options.barThickness, barSize),
+ helpers.getValueOrDefault(options.maxBarThickness, Infinity));
+
+ return {
+ stackCount: stackCount,
+ tickSize: tickSize,
+ categorySize: categorySize,
+ categorySpacing: tickSize - categorySize,
+ fullBarSize: fullBarSize,
+ barSize: barSize,
+ barSpacing: fullBarSize - barSize,
+ scale: scale
+ };
+ },
+
+ /**
+ * Note: pixel values are not clamped to the scale area.
+ * @private
+ */
+ calculateBarValuePixels: function(datasetIndex, index) {
+ var me = this;
+ var chart = me.chart;
+ var meta = me.getMeta();
+ var scale = me.getValueScale();
+ var datasets = chart.data.datasets;
+ var value = Number(datasets[datasetIndex].data[index]);
+ var stacked = scale.options.stacked;
+ var stack = meta.stack;
+ var start = 0;
+ var i, imeta, ivalue, base, head, size;
+
+ if (stacked || (stacked === undefined && stack !== undefined)) {
+ for (i = 0; i < datasetIndex; ++i) {
+ imeta = chart.getDatasetMeta(i);
+
+ if (imeta.bar &&
+ imeta.stack === stack &&
+ imeta.controller.getValueScaleId() === scale.id &&
+ chart.isDatasetVisible(i)) {
+
+ ivalue = Number(datasets[i].data[index]);
+ if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
+ start += ivalue;
+ }
+ }
+ }
+ }
+
+ base = scale.getPixelForValue(start);
+ head = scale.getPixelForValue(start + value);
+ size = (head - base) / 2;
+
+ return {
+ size: size,
+ base: base,
+ head: head,
+ center: head + size / 2
+ };
+ },
+
+ /**
+ * @private
+ */
+ calculateBarIndexPixels: function(datasetIndex, index, ruler) {
+ var me = this;
+ var scale = ruler.scale;
+ var isCombo = me.chart.isCombo;
+ var stackIndex = me.getStackIndex(datasetIndex);
+ var base = scale.getPixelForValue(null, index, datasetIndex, isCombo);
+ var size = ruler.barSize;
+
+ base -= isCombo? ruler.tickSize / 2 : 0;
+ base += ruler.fullBarSize * stackIndex;
+ base += ruler.categorySpacing / 2;
+ base += ruler.barSpacing / 2;
+
+ return {
+ size: size,
+ base: base,
+ head: base + size,
+ center: base + size / 2
+ };
+ },
+
+ draw: function() {
+ var me = this;
+ var chart = me.chart;
+ var elements = me.getMeta().data;
+ var dataset = me.getDataset();
+ var ilen = elements.length;
+ var i = 0;
+ var d;
+
+ helpers.canvas.clipArea(chart.ctx, chart.chartArea);
+
+ for (; i 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({
+ /**
+ * @private
+ */
+ getValueScaleId: function() {
+ return this.getMeta().xAxisID;
+ },
+
+ /**
+ * @private
+ */
+ getIndexScaleId: function() {
+ return this.getMeta().yAxisID;
+ }
+ });
+};
+
+},{}],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('');
+
+ var data = chart.data;
+ var datasets = data.datasets;
+ var labels = data.labels;
+
+ if (datasets.length) {
+ for (var i = 0; i < datasets[0].data.length; ++i) {
+ text.push(' ');
+ if (labels[i]) {
+ text.push(labels[i]);
+ }
+ text.push(' ');
+ }
+ }
+
+ text.push(' ');
+ return text.join('');
+ },
+ legend: {
+ labels: {
+ generateLabels: function(chart) {
+ var data = chart.data;
+ if (data.labels.length && data.datasets.length) {
+ return data.labels.map(function(label, i) {
+ var meta = chart.getDatasetMeta(0);
+ var ds = data.datasets[0];
+ var arc = meta.data[i];
+ var custom = arc && 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),
+ };
+
+ line.pivot();
+ }
+
+ // Update Points
+ for (i=0, ilen=points.length; i');
+
+ var data = chart.data;
+ var datasets = data.datasets;
+ var labels = data.labels;
+
+ if (datasets.length) {
+ for (var i = 0; i < datasets[0].data.length; ++i) {
+ text.push(' ');
+ if (labels[i]) {
+ text.push(labels[i]);
+ }
+ text.push(' ');
+ }
+ }
+
+ text.push('');
+ return text.join('');
+ },
+ legend: {
+ labels: {
+ generateLabels: function(chart) {
+ var data = chart.data;
+ if (data.labels.length && data.datasets.length) {
+ return data.labels.map(function(label, i) {
+ var meta = chart.getDatasetMeta(0);
+ var ds = data.datasets[0];
+ var arc = meta.data[i];
+ var custom = arc.custom || {};
+ var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
+ var arcOpts = chart.options.elements.arc;
+ var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
+ var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
+ var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
+
+ return {
+ text: label,
+ fillStyle: fill,
+ strokeStyle: stroke,
+ lineWidth: bw,
+ hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
+
+ // Extra data used for toggling the correct item
+ index: i
+ };
+ });
+ }
+ return [];
+ }
+ },
+
+ onClick: function(e, legendItem) {
+ var index = legendItem.index;
+ var chart = this.chart;
+ var i, ilen, meta;
+
+ for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+ meta = chart.getDatasetMeta(i);
+ meta.data[index].hidden = !meta.data[index].hidden;
+ }
+
+ chart.update();
+ }
+ },
+
+ // Need to override these to give a nice default
+ tooltips: {
+ callbacks: {
+ title: function() {
+ return '';
+ },
+ label: function(tooltipItem, data) {
+ return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
+ }
+ }
+ }
+ };
+
+ Chart.controllers.polarArea = Chart.DatasetController.extend({
+
+ dataElementType: Chart.elements.Arc,
+
+ linkScales: helpers.noop,
+
+ update: function(reset) {
+ var me = this;
+ var chart = me.chart;
+ var chartArea = chart.chartArea;
+ var meta = me.getMeta();
+ var opts = chart.options;
+ var arcOpts = opts.elements.arc;
+ var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
+ chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
+ chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
+ chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
+
+ me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
+ me.innerRadius = me.outerRadius - chart.radiusLength;
+
+ meta.count = me.countVisibleElements();
+
+ helpers.each(meta.data, function(arc, index) {
+ me.updateElement(arc, index, reset);
+ });
+ },
+
+ updateElement: function(arc, index, reset) {
+ var me = this;
+ var chart = me.chart;
+ var dataset = me.getDataset();
+ var opts = chart.options;
+ var animationOpts = opts.animation;
+ var scale = chart.scale;
+ var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
+ var labels = chart.data.labels;
+
+ var circumference = me.calculateCircumference(dataset.data[index]);
+ var centerX = scale.xCenter;
+ var centerY = scale.yCenter;
+
+ // If there is NaN data before us, we need to calculate the starting angle correctly.
+ // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
+ var visibleCount = 0;
+ var meta = me.getMeta();
+ for (var i = 0; i < index; ++i) {
+ if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
+ ++visibleCount;
+ }
+ }
+
+ // var negHalfPI = -0.5 * Math.PI;
+ var datasetStartAngle = opts.startAngle;
+ var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+ var startAngle = datasetStartAngle + (circumference * visibleCount);
+ var endAngle = startAngle + (arc.hidden ? 0 : circumference);
+
+ var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+
+ helpers.extend(arc, {
+ // Utility
+ _datasetIndex: me.index,
+ _index: index,
+ _scale: scale,
+
+ // Desired view properties
+ _model: {
+ x: centerX,
+ y: centerY,
+ innerRadius: 0,
+ outerRadius: reset ? resetRadius : distance,
+ startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
+ endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
+ label: getValueAtIndexOrDefault(labels, index, labels[index])
+ }
+ });
+
+ // Apply border and fill style
+ me.removeHoverStyle(arc);
+
+ arc.pivot();
+ },
+
+ removeHoverStyle: function(arc) {
+ Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
+ },
+
+ countVisibleElements: function() {
+ var dataset = this.getDataset();
+ var meta = this.getMeta();
+ var count = 0;
+
+ helpers.each(meta.data, function(element, index) {
+ if (!isNaN(dataset.data[index]) && !element.hidden) {
+ count++;
+ }
+ });
+
+ return count;
+ },
+
+ calculateCircumference: function(value) {
+ var count = this.getMeta().count;
+ if (count > 0 && !isNaN(value)) {
+ return (2 * Math.PI) / count;
+ }
+ return 0;
+ }
+ });
+};
+
+},{}],20:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ Chart.defaults.radar = {
+ aspectRatio: 1,
+ scale: {
+ type: 'radialLinear'
+ },
+ elements: {
+ line: {
+ tension: 0 // no bezier in radar
+ }
+ }
+ };
+
+ Chart.controllers.radar = Chart.DatasetController.extend({
+
+ datasetElementType: Chart.elements.Line,
+
+ dataElementType: Chart.elements.Point,
+
+ linkScales: helpers.noop,
+
+ update: function(reset) {
+ var me = this;
+ var meta = me.getMeta();
+ var line = meta.dataset;
+ var points = meta.data;
+ var custom = line.custom || {};
+ var dataset = me.getDataset();
+ var lineElementOptions = me.chart.options.elements.line;
+ var scale = me.chart.scale;
+
+ // Compatibility: If the properties are defined with only the old name, use those values
+ if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
+ dataset.lineTension = dataset.tension;
+ }
+
+ helpers.extend(meta.dataset, {
+ // Utility
+ _datasetIndex: me.index,
+ _scale: scale,
+ // 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),
+ }
+ });
+
+ 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]);
+
+ // 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;
+ }
+
+ 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.pointHitRadius, 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();
+ });
+ },
+
+ 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.pointRadius, 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({
+ chart: null, // the animation associated chart instance
+ currentStep: 0, // 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,
+
+ /**
+ * @param {Chart} chart - The chart to animate.
+ * @param {Chart.Animation} animation - The animation that we will animate.
+ * @param {Number} duration - The animation duration in ms.
+ * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
+ */
+ addAnimation: function(chart, animation, duration, lazy) {
+ var animations = this.animations;
+ var i, ilen;
+
+ animation.chart = chart;
+
+ if (!lazy) {
+ chart.animating = true;
+ }
+
+ for (i=0, ilen=animations.length; i < ilen; ++i) {
+ if (animations[i].chart === chart) {
+ animations[i] = animation;
+ return;
+ }
+ }
+
+ animations.push(animation);
+
+ // If there are no animations queued, manually kickstart a digest, for lack of a better word
+ if (animations.length === 1) {
+ this.requestAnimationFrame();
+ }
+ },
+
+ cancelAnimation: function(chart) {
+ var index = helpers.findIndex(this.animations, function(animation) {
+ return animation.chart === chart;
+ });
+
+ if (index !== -1) {
+ this.animations.splice(index, 1);
+ chart.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();
+ });
+ }
+ },
+
+ /**
+ * @private
+ */
+ 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;
+ }
+
+ me.advance(1 + framesToDrop);
+
+ var endTime = Date.now();
+
+ me.dropFrames += (endTime - startTime) / me.frameDuration;
+
+ // Do we have more stuff to animate?
+ if (me.animations.length > 0) {
+ me.requestAnimationFrame();
+ }
+ },
+
+ /**
+ * @private
+ */
+ advance: function(count) {
+ var animations = this.animations;
+ var animation, chart;
+ var i = 0;
+
+ while (i < animations.length) {
+ animation = animations[i];
+ chart = animation.chart;
+
+ animation.currentStep = (animation.currentStep || 0) + count;
+ animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
+
+ helpers.callback(animation.render, [chart, animation], chart);
+ helpers.callback(animation.onAnimationProgress, [animation], chart);
+
+ if (animation.currentStep >= animation.numSteps) {
+ helpers.callback(animation.onAnimationComplete, [animation], chart);
+ chart.animating = false;
+ animations.splice(i, 1);
+ } else {
+ ++i;
+ }
+ }
+ }
+ };
+
+ /**
+ * Provided for backward compatibility, use Chart.Animation instead
+ * @prop Chart.Animation#animationObject
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+ Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
+ get: function() {
+ return this;
+ }
+ });
+
+ /**
+ * Provided for backward compatibility, use Chart.Animation#chart instead
+ * @prop Chart.Animation#chartInstance
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+ Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
+ get: function() {
+ return this.chart;
+ },
+ set: function(value) {
+ this.chart = value;
+ }
+ });
+
+};
+
+},{}],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, pointStyle.width, pointStyle.height);
+ 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();
+ };
+
+ helpers.lineTo = function(ctx, previous, target, flip) {
+ if (target.steppedLine) {
+ if (target.steppedLine === 'after') {
+ ctx.lineTo(previous.x, target.y);
+ } else {
+ ctx.lineTo(target.x, previous.y);
+ }
+ ctx.lineTo(target.x, target.y);
+ return;
+ }
+
+ if (!target.tension) {
+ ctx.lineTo(target.x, target.y);
+ return;
+ }
+
+ ctx.bezierCurveTo(
+ flip? previous.controlPointPreviousX : previous.controlPointNextX,
+ flip? previous.controlPointPreviousY : previous.controlPointNextY,
+ flip? target.controlPointNextX : target.controlPointPreviousX,
+ flip? target.controlPointNextY : target.controlPointPreviousY,
+ target.x,
+ target.y);
+ };
+
+ Chart.helpers.canvas = helpers;
+};
+
+},{}],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} 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;
+ }
+
+ function positionIsHorizontal(position) {
+ return position === 'top' || position === 'bottom';
+ }
+
+ helpers.extend(Chart.prototype, /** @lends Chart */ {
+ /**
+ * @private
+ */
+ construct: function(item, config) {
+ 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;
+
+ me.id = helpers.uid();
+ me.ctx = context;
+ me.canvas = canvas;
+ me.config = config;
+ me.width = width;
+ me.height = height;
+ me.aspectRatio = height? width / height : null;
+ me.options = config.options;
+ me._bufferedRender = false;
+
+ /**
+ * Provided for backward compatibility, Chart and Chart.Controller have been merged,
+ * the "instance" still need to be defined since it might be called from plugins.
+ * @prop Chart#chart
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ * @private
+ */
+ me.chart = me;
+ me.controller = me; // chart.chart.controller #inception
+
+ // Add the chart instance to the global namespace
+ Chart.instances[me.id] = me;
+
+ // Define alias to the config data: `chart.data === chart.config.data`
+ Object.defineProperty(me, 'data', {
+ get: function() {
+ return me.config.data;
+ },
+ set: function(value) {
+ me.config.data = value;
+ }
+ });
+
+ 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.initialize();
+ me.update();
+ },
+
+ /**
+ * @private
+ */
+ initialize: function() {
+ var me = this;
+
+ // Before init plugin notification
+ plugins.notify(me, 'beforeInit');
+
+ helpers.retinaScale(me);
+
+ 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);
+ return this;
+ },
+
+ stop: function() {
+ // Stops any current animation loop occurring
+ Chart.animationService.cancelAnimation(this);
+ return this;
+ },
+
+ resize: function(silent) {
+ var me = this;
+ var options = me.options;
+ var canvas = me.canvas;
+ var aspectRatio = (options.maintainAspectRatio && me.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 (me.width === newWidth && me.height === newHeight) {
+ return;
+ }
+
+ canvas.width = me.width = newWidth;
+ canvas.height = me.height = newHeight;
+ canvas.style.width = newWidth + 'px';
+ canvas.style.height = newHeight + 'px';
+
+ helpers.retinaScale(me);
+
+ 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', dposition: 'bottom'};
+ }),
+ (options.scales.yAxes || []).map(function(yAxisOptions) {
+ return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
+ })
+ );
+ }
+
+ if (options.scale) {
+ items.push({
+ options: options.scale,
+ dtype: 'radialLinear',
+ isDefault: true,
+ dposition: 'chartArea'
+ });
+ }
+
+ 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;
+ }
+
+ if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
+ scaleOptions.position = item.dposition;
+ }
+
+ var scale = new scaleClass({
+ id: scaleOptions.id,
+ options: scaleOptions,
+ ctx: me.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 {
+ var ControllerClass = Chart.controllers[meta.type];
+ if (ControllerClass === undefined) {
+ throw new Error('"' + meta.type + '" is not a chart type.');
+ }
+
+ meta.controller = new ControllerClass(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.width, this.height);
+
+ /**
+ * Provided for backward compatibility, use `afterLayout` instead.
+ * @method IPlugin#afterScaleUpdate
+ * @deprecated since version 2.5.0
+ * @todo remove at version 3
+ * @private
+ */
+ 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.updateDataset(i);
+ }
+
+ plugins.notify(me, 'afterDatasetsUpdate');
+ },
+
+ /**
+ * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
+ * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
+ * @private
+ */
+ updateDataset: function(index) {
+ var me = this;
+ var meta = me.getDatasetMeta(index);
+ var args = {
+ meta: meta,
+ index: index
+ };
+
+ if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
+ return;
+ }
+
+ meta.controller.update();
+
+ plugins.notify(me, 'afterDatasetUpdate', [args]);
+ },
+
+ render: function(duration, lazy) {
+ var me = this;
+
+ if (plugins.notify(me, 'beforeRender') === false) {
+ return;
+ }
+
+ var animationOptions = me.options.animation;
+ var onComplete = function(animation) {
+ plugins.notify(me, 'afterRender');
+ helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
+ };
+
+ if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
+ var animation = new Chart.Animation({
+ numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
+ easing: animationOptions.easing,
+
+ render: function(chart, animationObject) {
+ var easingFunction = helpers.easingEffects[animationObject.easing];
+ var currentStep = animationObject.currentStep;
+ var stepDecimal = currentStep / animationObject.numSteps;
+
+ chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
+ },
+
+ onAnimationProgress: animationOptions.onProgress,
+ onAnimationComplete: onComplete
+ });
+
+ Chart.animationService.addAnimation(me, animation, duration, lazy);
+ } else {
+ me.draw();
+
+ // See https://github.com/chartjs/Chart.js/issues/3781
+ onComplete(new Chart.Animation({numSteps: 0, chart: me}));
+ }
+
+ return me;
+ },
+
+ draw: function(easingValue) {
+ var me = this;
+
+ me.clear();
+
+ if (easingValue === undefined || easingValue === null) {
+ easingValue = 1;
+ }
+
+ me.transition(easingValue);
+
+ 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.draw();
+
+ plugins.notify(me, 'afterDraw', [easingValue]);
+ },
+
+ /**
+ * @private
+ */
+ transition: function(easingValue) {
+ var me = this;
+
+ for (var i=0, ilen=(me.data.datasets || []).length; i= 0; --i) {
+ if (me.isDatasetVisible(i)) {
+ me.drawDataset(i, easingValue);
+ }
+ }
+
+ plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
+ },
+
+ /**
+ * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
+ * hook, in which case, plugins will not be called on `afterDatasetDraw`.
+ * @private
+ */
+ drawDataset: function(index, easingValue) {
+ var me = this;
+ var meta = me.getDatasetMeta(index);
+ var args = {
+ meta: meta,
+ index: index,
+ easingValue: easingValue
+ };
+
+ if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
+ return;
+ }
+
+ meta.controller.draw(easingValue);
+
+ plugins.notify(me, 'afterDatasetDraw', [args]);
+ },
+
+ // 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 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,
+ _datasetIndex: me.index
+ });
+ },
+
+ createMetaData: function(index) {
+ var me = this;
+ var type = me.dataElementType;
+ return type && new type({
+ _chart: me.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 numMeta) {
+ me.insertElements(numMeta, numData - numMeta);
+ }
+ },
+
+ /**
+ * @private
+ */
+ insertElements: function(start, count) {
+ for (var i=0; i No Transition
+ if (!model || ease === 1) {
+ me._view = model;
+ me._start = null;
+ return me;
+ }
+
+ if (!view) {
+ view = me._view = {};
+ }
+
+ if (!start) {
+ start = me._start = {};
+ }
+
+ interpolate(start, view, model, ease);
+
+ 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;
+};
+
+},{"2":2}],26:[function(require,module,exports){
+/* global window: false */
+/* global document: false */
+'use strict';
+
+var color = require(2);
+
+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) {
+ return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
+ }
+ return index <= 0 ? collection[0] : collection[index - 1];
+ };
+ // Implementation of the nice number algorithm used in determining where axis labels will go
+ helpers.niceNum = function(range, round) {
+ var exponent = Math.floor(helpers.log10(range));
+ var fraction = range / Math.pow(10, exponent);
+ var niceFraction;
+
+ if (round) {
+ if (fraction < 1.5) {
+ niceFraction = 1;
+ } else if (fraction < 3) {
+ niceFraction = 2;
+ } else if (fraction < 7) {
+ niceFraction = 5;
+ } else {
+ niceFraction = 10;
+ }
+ } else if (fraction <= 1.0) {
+ niceFraction = 1;
+ } else if (fraction <= 2) {
+ niceFraction = 2;
+ } else if (fraction <= 5) {
+ niceFraction = 5;
+ } else {
+ niceFraction = 10;
+ }
+
+ return niceFraction * Math.pow(10, exponent);
+ };
+ // Easing functions adapted from Robert Penner's easing equations
+ // http://www.robertpenner.com/easing/
+ var easingEffects = helpers.easingEffects = {
+ linear: function(t) {
+ return t;
+ },
+ easeInQuad: function(t) {
+ return t * t;
+ },
+ easeOutQuad: function(t) {
+ return -1 * t * (t - 2);
+ },
+ easeInOutQuad: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t;
+ }
+ return -1 / 2 * ((--t) * (t - 2) - 1);
+ },
+ easeInCubic: function(t) {
+ return t * t * t;
+ },
+ easeOutCubic: function(t) {
+ return 1 * ((t = t / 1 - 1) * t * t + 1);
+ },
+ easeInOutCubic: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t;
+ }
+ return 1 / 2 * ((t -= 2) * t * t + 2);
+ },
+ easeInQuart: function(t) {
+ return t * t * t * t;
+ },
+ easeOutQuart: function(t) {
+ return -1 * ((t = t / 1 - 1) * t * t * t - 1);
+ },
+ easeInOutQuart: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t * t;
+ }
+ return -1 / 2 * ((t -= 2) * t * t * t - 2);
+ },
+ easeInQuint: function(t) {
+ return 1 * (t /= 1) * t * t * t * t;
+ },
+ easeOutQuint: function(t) {
+ return 1 * ((t = t / 1 - 1) * t * t * t * t + 1);
+ },
+ easeInOutQuint: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t * t * t;
+ }
+ return 1 / 2 * ((t -= 2) * t * t * t * t + 2);
+ },
+ easeInSine: function(t) {
+ return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1;
+ },
+ easeOutSine: function(t) {
+ return 1 * Math.sin(t / 1 * (Math.PI / 2));
+ },
+ easeInOutSine: function(t) {
+ return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1);
+ },
+ easeInExpo: function(t) {
+ return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1));
+ },
+ easeOutExpo: function(t) {
+ return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1);
+ },
+ easeInOutExpo: function(t) {
+ if (t === 0) {
+ return 0;
+ }
+ if (t === 1) {
+ return 1;
+ }
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * Math.pow(2, 10 * (t - 1));
+ }
+ return 1 / 2 * (-Math.pow(2, -10 * --t) + 2);
+ },
+ easeInCirc: function(t) {
+ if (t >= 1) {
+ return t;
+ }
+ return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1);
+ },
+ easeOutCirc: function(t) {
+ return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t);
+ },
+ easeInOutCirc: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return -1 / 2 * (Math.sqrt(1 - t * t) - 1);
+ }
+ return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1);
+ },
+ easeInElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1) === 1) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * 0.3;
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
+ },
+ easeOutElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1) === 1) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * 0.3;
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
+ },
+ easeInOutElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1 / 2) === 2) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * (0.3 * 1.5);
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ if (t < 1) {
+ return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
+ }
+ return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1;
+ },
+ easeInBack: function(t) {
+ var s = 1.70158;
+ return 1 * (t /= 1) * t * ((s + 1) * t - s);
+ },
+ easeOutBack: function(t) {
+ var s = 1.70158;
+ return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1);
+ },
+ easeInOutBack: function(t) {
+ var s = 1.70158;
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s));
+ }
+ return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
+ },
+ easeInBounce: function(t) {
+ return 1 - easingEffects.easeOutBounce(1 - t);
+ },
+ easeOutBounce: function(t) {
+ if ((t /= 1) < (1 / 2.75)) {
+ return 1 * (7.5625 * t * t);
+ } else if (t < (2 / 2.75)) {
+ return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
+ } else if (t < (2.5 / 2.75)) {
+ return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
+ }
+ return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
+ },
+ easeInOutBounce: function(t) {
+ if (t < 1 / 2) {
+ return easingEffects.easeInBounce(t * 2) * 0.5;
+ }
+ return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
+ }
+ };
+ // Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
+ helpers.requestAnimFrame = (function() {
+ if (typeof window === 'undefined') {
+ return function(callback) {
+ callback();
+ };
+ }
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback) {
+ return window.setTimeout(callback, 1000 / 60);
+ };
+ }());
+ // -- DOM methods
+ helpers.getRelativePosition = function(evt, chart) {
+ var mouseX, mouseY;
+ var e = evt.originalEvent || evt,
+ canvas = evt.currentTarget || evt.srcElement,
+ boundingRect = canvas.getBoundingClientRect();
+
+ var touches = e.touches;
+ if (touches && touches.length > 0) {
+ mouseX = touches[0].clientX;
+ mouseY = touches[0].clientY;
+
+ } else {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ }
+
+ // Scale mouse coordinates into canvas coordinates
+ // by following the pattern laid out by 'jerryj' in the comments of
+ // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
+ var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
+ var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
+ var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
+ var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
+ var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
+ var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
+
+ // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
+ // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
+ mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
+ mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
+
+ return {
+ x: mouseX,
+ y: mouseY
+ };
+
+ };
+ helpers.addEvent = function(node, eventType, method) {
+ if (node.addEventListener) {
+ node.addEventListener(eventType, method);
+ } else if (node.attachEvent) {
+ node.attachEvent('on' + eventType, method);
+ } else {
+ node['on' + eventType] = method;
+ }
+ };
+ helpers.removeEvent = function(node, eventType, handler) {
+ if (node.removeEventListener) {
+ node.removeEventListener(eventType, handler, false);
+ } else if (node.detachEvent) {
+ node.detachEvent('on' + eventType, handler);
+ } else {
+ node['on' + eventType] = helpers.noop;
+ }
+ };
+
+ // Private helper function to convert max-width/max-height values that may be percentages into a number
+ function parseMaxStyle(styleValue, node, parentProperty) {
+ var valueInPixels;
+ if (typeof(styleValue) === 'string') {
+ valueInPixels = parseInt(styleValue, 10);
+
+ if (styleValue.indexOf('%') !== -1) {
+ // percentage * size in dimension
+ valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
+ }
+ } else {
+ valueInPixels = styleValue;
+ }
+
+ return valueInPixels;
+ }
+
+ /**
+ * Returns if the given value contains an effective constraint.
+ * @private
+ */
+ function isConstrainedValue(value) {
+ return value !== undefined && value !== null && value !== 'none';
+ }
+
+ // Private helper to get a constraint dimension
+ // @param domNode : the node to check the constraint on
+ // @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
+ // @param percentageProperty : property of parent to use when calculating width as a percentage
+ // @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
+ function getConstraintDimension(domNode, maxStyle, percentageProperty) {
+ var view = document.defaultView;
+ var parentNode = domNode.parentNode;
+ var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
+ var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
+ var hasCNode = isConstrainedValue(constrainedNode);
+ var hasCContainer = isConstrainedValue(constrainedContainer);
+ var infinity = Number.POSITIVE_INFINITY;
+
+ if (hasCNode || hasCContainer) {
+ return Math.min(
+ hasCNode? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
+ hasCContainer? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
+ }
+
+ return 'none';
+ }
+ // returns Number or undefined if no constraint
+ helpers.getConstraintWidth = function(domNode) {
+ return getConstraintDimension(domNode, 'max-width', 'clientWidth');
+ };
+ // returns Number or undefined if no constraint
+ helpers.getConstraintHeight = function(domNode) {
+ return getConstraintDimension(domNode, 'max-height', 'clientHeight');
+ };
+ helpers.getMaximumWidth = function(domNode) {
+ var container = domNode.parentNode;
+ var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10);
+ var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10);
+ var w = container.clientWidth - paddingLeft - paddingRight;
+ var cw = helpers.getConstraintWidth(domNode);
+ return isNaN(cw)? w : Math.min(w, cw);
+ };
+ helpers.getMaximumHeight = function(domNode) {
+ var container = domNode.parentNode;
+ var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10);
+ var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10);
+ var h = container.clientHeight - paddingTop - paddingBottom;
+ var ch = helpers.getConstraintHeight(domNode);
+ return isNaN(ch)? h : Math.min(h, ch);
+ };
+ helpers.getStyle = function(el, property) {
+ return el.currentStyle ?
+ el.currentStyle[property] :
+ document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
+ };
+ helpers.retinaScale = function(chart) {
+ var pixelRatio = chart.currentDevicePixelRatio = window.devicePixelRatio || 1;
+ if (pixelRatio === 1) {
+ return;
+ }
+
+ var canvas = chart.canvas;
+ var height = chart.height;
+ var width = chart.width;
+
+ canvas.height = height * pixelRatio;
+ canvas.width = width * pixelRatio;
+ chart.ctx.scale(pixelRatio, pixelRatio);
+
+ // If no style has been set on the canvas, the render size is used as display size,
+ // making the chart visually bigger, so let's enforce it to the "correct" values.
+ // See https://github.com/chartjs/Chart.js/issues/3575
+ canvas.style.height = height + 'px';
+ canvas.style.width = width + 'px';
+ };
+ // -- Canvas methods
+ helpers.clear = function(chart) {
+ chart.ctx.clearRect(0, 0, chart.width, chart.height);
+ };
+ helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
+ return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
+ };
+ helpers.longestText = function(ctx, font, arrayOfThings, cache) {
+ cache = cache || {};
+ var data = cache.data = cache.data || {};
+ var gc = cache.garbageCollect = cache.garbageCollect || [];
+
+ if (cache.font !== font) {
+ data = cache.data = {};
+ gc = cache.garbageCollect = [];
+ cache.font = font;
+ }
+
+ ctx.font = font;
+ var longest = 0;
+ helpers.each(arrayOfThings, function(thing) {
+ // Undefined strings and arrays should not be measured
+ if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
+ longest = helpers.measureText(ctx, data, gc, longest, thing);
+ } else if (helpers.isArray(thing)) {
+ // if it is an array lets measure each element
+ // to do maybe simplify this function a bit so we can do this more recursively?
+ helpers.each(thing, function(nestedThing) {
+ // Undefined strings and arrays should not be measured
+ if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
+ longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
+ }
+ });
+ }
+ });
+
+ var gcLen = gc.length / 2;
+ if (gcLen > arrayOfThings.length) {
+ for (var i = 0; i < gcLen; i++) {
+ delete data[gc[i]];
+ }
+ gc.splice(0, gcLen);
+ }
+ return longest;
+ };
+ helpers.measureText = function(ctx, data, gc, longest, string) {
+ var textWidth = data[string];
+ if (!textWidth) {
+ textWidth = data[string] = ctx.measureText(string).width;
+ gc.push(string);
+ }
+ if (textWidth > longest) {
+ longest = textWidth;
+ }
+ return longest;
+ };
+ helpers.numberOfLabelLines = function(arrayOfThings) {
+ var numberOfLines = 1;
+ helpers.each(arrayOfThings, function(thing) {
+ if (helpers.isArray(thing)) {
+ if (thing.length > numberOfLines) {
+ numberOfLines = thing.length;
+ }
+ }
+ });
+ return numberOfLines;
+ };
+ helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) {
+ ctx.beginPath();
+ ctx.moveTo(x + radius, y);
+ ctx.lineTo(x + width - radius, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+ ctx.lineTo(x + radius, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+ ctx.lineTo(x, y + radius);
+ ctx.quadraticCurveTo(x, y, x + radius, y);
+ ctx.closePath();
+ };
+
+ helpers.color = !color?
+ function(value) {
+ console.error('Color.js not found!');
+ return value;
+ } :
+ function(value) {
+ /* global CanvasGradient */
+ if (value instanceof CanvasGradient) {
+ value = Chart.defaults.global.defaultColor;
+ }
+
+ return color(value);
+ };
+
+ helpers.isArray = Array.isArray?
+ function(obj) {
+ return Array.isArray(obj);
+ } :
+ function(obj) {
+ return Object.prototype.toString.call(obj) === '[object Array]';
+ };
+ // ! @see http://stackoverflow.com/a/14853974
+ helpers.arrayEquals = function(a0, a1) {
+ var i, ilen, v0, v1;
+
+ if (!a0 || !a1 || a0.length !== a1.length) {
+ return false;
+ }
+
+ for (i = 0, ilen=a0.length; i < ilen; ++i) {
+ v0 = a0[i];
+ v1 = a1[i];
+
+ if (v0 instanceof Array && v1 instanceof Array) {
+ if (!helpers.arrayEquals(v0, v1)) {
+ return false;
+ }
+ } else if (v0 !== v1) {
+ // NOTE: two different object instances will never be equal: {x:20} != {x:20}
+ return false;
+ }
+ }
+
+ return true;
+ };
+ helpers.callback = function(fn, args, thisArg) {
+ if (fn && typeof fn.call === 'function') {
+ fn.apply(thisArg, args);
+ }
+ };
+ helpers.getHoverColor = function(colorValue) {
+ /* global CanvasPattern */
+ return (colorValue instanceof CanvasPattern) ?
+ colorValue :
+ helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
+ };
+
+ /**
+ * Provided for backward compatibility, use Chart.helpers#callback instead.
+ * @function Chart.helpers#callCallback
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+ helpers.callCallback = helpers.callback;
+};
+
+},{"2":2}],27:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+ var helpers = Chart.helpers;
+
+ /**
+ * Helper function to get relative position for an event
+ * @param {Event|IEvent} event - The event to get the position for
+ * @param {Chart} chart - The chart
+ * @returns {Point} the event position
+ */
+ function getRelativePosition(e, chart) {
+ if (e.native) {
+ return {
+ x: e.x,
+ y: e.y
+ };
+ }
+
+ return helpers.getRelativePosition(e, chart);
+ }
+
+ /**
+ * Helper function to traverse all of the visible elements in the chart
+ * @param chart {chart} the chart
+ * @param handler {Function} the callback to execute for each visible item
+ */
+ function parseVisibleItems(chart, handler) {
+ var datasets = chart.data.datasets;
+ var meta, i, j, ilen, jlen;
+
+ for (i = 0, ilen = datasets.length; i < ilen; ++i) {
+ if (!chart.isDatasetVisible(i)) {
+ continue;
+ }
+
+ meta = chart.getDatasetMeta(i);
+ for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
+ var element = meta.data[j];
+ if (!element._view.skip) {
+ handler(element);
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper function to get the items that intersect the event position
+ * @param items {ChartElement[]} elements to filter
+ * @param position {Point} the point to be nearest to
+ * @return {ChartElement[]} the nearest items
+ */
+ function getIntersectItems(chart, position) {
+ var elements = [];
+
+ parseVisibleItems(chart, function(element) {
+ if (element.inRange(position.x, position.y)) {
+ elements.push(element);
+ }
+ });
+
+ return elements;
+ }
+
+ /**
+ * Helper function to get the items nearest to the event position considering all visible items in teh chart
+ * @param chart {Chart} the chart to look at elements from
+ * @param position {Point} the point to be nearest to
+ * @param intersect {Boolean} if true, only consider items that intersect the position
+ * @param distanceMetric {Function} Optional function to provide the distance between
+ * @return {ChartElement[]} the nearest items
+ */
+ function getNearestItems(chart, position, intersect, distanceMetric) {
+ var minDistance = Number.POSITIVE_INFINITY;
+ var nearestItems = [];
+
+ if (!distanceMetric) {
+ distanceMetric = helpers.distanceBetweenPoints;
+ }
+
+ parseVisibleItems(chart, function(element) {
+ if (intersect && !element.inRange(position.x, position.y)) {
+ return;
+ }
+
+ var center = element.getCenterPoint();
+ var distance = distanceMetric(position, center);
+
+ if (distance < minDistance) {
+ nearestItems = [element];
+ minDistance = distance;
+ } else if (distance === minDistance) {
+ // Can have multiple items at the same distance in which case we sort by size
+ nearestItems.push(element);
+ }
+ });
+
+ return nearestItems;
+ }
+
+ function indexMode(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var distanceMetric = function(pt1, pt2) {
+ return Math.abs(pt1.x - pt2.x);
+ };
+ var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
+ var elements = [];
+
+ if (!items.length) {
+ return [];
+ }
+
+ chart.data.datasets.forEach(function(dataset, datasetIndex) {
+ if (chart.isDatasetVisible(datasetIndex)) {
+ var meta = chart.getDatasetMeta(datasetIndex),
+ element = meta.data[items[0]._index];
+
+ // don't count items that are skipped (null data)
+ if (element && !element._view.skip) {
+ elements.push(element);
+ }
+ }
+ });
+
+ return elements;
+ }
+
+ /**
+ * @interface IInteractionOptions
+ */
+ /**
+ * If true, only consider items that intersect the point
+ * @name IInterfaceOptions#boolean
+ * @type Boolean
+ */
+
+ /**
+ * Contains interaction related functions
+ * @namespace Chart.Interaction
+ */
+ Chart.Interaction = {
+ // Helper function for different modes
+ modes: {
+ single: function(chart, e) {
+ var position = getRelativePosition(e, chart);
+ var elements = [];
+
+ parseVisibleItems(chart, function(element) {
+ if (element.inRange(position.x, position.y)) {
+ elements.push(element);
+ return elements;
+ }
+ });
+
+ return elements.slice(0, 1);
+ },
+
+ /**
+ * @function Chart.Interaction.modes.label
+ * @deprecated since version 2.4.0
+ * @todo remove at version 3
+ * @private
+ */
+ label: indexMode,
+
+ /**
+ * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
+ * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
+ * @function Chart.Interaction.modes.index
+ * @since v2.4.0
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use during interaction
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ index: indexMode,
+
+ /**
+ * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
+ * If the options.intersect is false, we find the nearest item and return the items in that dataset
+ * @function Chart.Interaction.modes.dataset
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use during interaction
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ dataset: function(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false);
+
+ if (items.length > 0) {
+ items = chart.getDatasetMeta(items[0]._datasetIndex).data;
+ }
+
+ return items;
+ },
+
+ /**
+ * @function Chart.Interaction.modes.x-axis
+ * @deprecated since version 2.4.0. Use index mode and intersect == true
+ * @todo remove at version 3
+ * @private
+ */
+ 'x-axis': function(chart, e) {
+ return indexMode(chart, e, true);
+ },
+
+ /**
+ * Point mode returns all elements that hit test based on the event position
+ * of the event
+ * @function Chart.Interaction.modes.intersect
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ point: function(chart, e) {
+ var position = getRelativePosition(e, chart);
+ return getIntersectItems(chart, position);
+ },
+
+ /**
+ * nearest mode returns the element closest to the point
+ * @function Chart.Interaction.modes.intersect
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ nearest: function(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var nearestItems = getNearestItems(chart, position, options.intersect);
+
+ // We have multiple items at the same distance from the event. Now sort by smallest
+ if (nearestItems.length > 1) {
+ nearestItems.sort(function(a, b) {
+ var sizeA = a.getArea();
+ var sizeB = b.getArea();
+ var ret = sizeA - sizeB;
+
+ if (ret === 0) {
+ // if equal sort by dataset index
+ ret = a._datasetIndex - b._datasetIndex;
+ }
+
+ return ret;
+ });
+ }
+
+ // Return only 1 item
+ return nearestItems.slice(0, 1);
+ },
+
+ /**
+ * x mode returns the elements that hit-test at the current x coordinate
+ * @function Chart.Interaction.modes.x
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ x: function(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var items = [];
+ var intersectsItem = false;
+
+ parseVisibleItems(chart, function(element) {
+ if (element.inXRange(position.x)) {
+ items.push(element);
+ }
+
+ if (element.inRange(position.x, position.y)) {
+ intersectsItem = true;
+ }
+ });
+
+ // If we want to trigger on an intersect and we don't have any items
+ // that intersect the position, return nothing
+ if (options.intersect && !intersectsItem) {
+ items = [];
+ }
+ return items;
+ },
+
+ /**
+ * y mode returns the elements that hit-test at the current y coordinate
+ * @function Chart.Interaction.modes.y
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ y: function(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var items = [];
+ var intersectsItem = false;
+
+ parseVisibleItems(chart, function(element) {
+ if (element.inYRange(position.y)) {
+ items.push(element);
+ }
+
+ if (element.inRange(position.x, position.y)) {
+ intersectsItem = true;
+ }
+ });
+
+ // If we want to trigger on an intersect and we don't have any items
+ // that intersect the position, return nothing
+ if (options.intersect && !intersectsItem) {
+ items = [];
+ }
+ return items;
+ }
+ }
+ };
+};
+
+},{}],28:[function(require,module,exports){
+'use strict';
+
+module.exports = function() {
+
+ // Occupy the global variable of Chart, and create a simple base class
+ var Chart = function(item, config) {
+ this.construct(item, config);
+ return this;
+ };
+
+ // Globally expose the defaults to allow for user updating/changing
+ Chart.defaults = {
+ global: {
+ responsive: true,
+ responsiveAnimationDuration: 0,
+ maintainAspectRatio: true,
+ events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
+ hover: {
+ onHover: null,
+ mode: 'nearest',
+ intersect: true,
+ animationDuration: 400
+ },
+ onClick: null,
+ defaultColor: 'rgba(0,0,0,0.1)',
+ defaultFontColor: '#666',
+ defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+ defaultFontSize: 12,
+ defaultFontStyle: 'normal',
+ showLines: true,
+
+ // Element defaults defined in element extensions
+ elements: {},
+
+ // Legend callback string
+ legendCallback: function(chart) {
+ var text = [];
+ text.push('');
+ for (var i = 0; i < chart.data.datasets.length; i++) {
+ text.push(' ');
+ if (chart.data.datasets[i].label) {
+ text.push(chart.data.datasets[i].label);
+ }
+ text.push(' ');
+ }
+ text.push(' ');
+
+ return text.join('');
+ }
+ }
+ };
+
+ Chart.Chart = Chart;
+
+ return Chart;
+};
+
+},{}],29:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ function filterByPosition(array, position) {
+ return helpers.where(array, function(v) {
+ return v.position === position;
+ });
+ }
+
+ function sortByWeight(array, reverse) {
+ array.forEach(function(v, i) {
+ v._tmpIndex_ = i;
+ return v;
+ });
+ array.sort(function(a, b) {
+ var v0 = reverse ? b : a;
+ var v1 = reverse ? a : b;
+ return v0.weight === v1.weight ?
+ v0._tmpIndex_ - v1._tmpIndex_ :
+ v0.weight - v1.weight;
+ });
+ array.forEach(function(v) {
+ delete v._tmpIndex_;
+ });
+ }
+
+ /**
+ * @interface ILayoutItem
+ * @prop {String} position - The position of the item in the chart layout. Possible values are
+ * 'left', 'top', 'right', 'bottom', and 'chartArea'
+ * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
+ * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
+ * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
+ * @prop {Function} update - Takes two parameters: width and height. Returns size of item
+ * @prop {Function} getPadding - Returns an object with padding on the edges
+ * @prop {Number} width - Width of item. Must be valid after update()
+ * @prop {Number} height - Height of item. Must be valid after update()
+ * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
+ */
+
+ // The layout service is very self explanatory. It's responsible for the layout within a chart.
+ // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
+ // It is this service's responsibility of carrying out that layout.
+ Chart.layoutService = {
+ defaults: {},
+
+ /**
+ * Register a box to a chart.
+ * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
+ * @param {Chart} chart - the chart to use
+ * @param {ILayoutItem} item - the item to add to be layed out
+ */
+ addBox: function(chart, item) {
+ if (!chart.boxes) {
+ chart.boxes = [];
+ }
+
+ // initialize item with default values
+ item.fullWidth = item.fullWidth || false;
+ item.position = item.position || 'top';
+ item.weight = item.weight || 0;
+
+ chart.boxes.push(item);
+ },
+
+ /**
+ * Remove a layoutItem from a chart
+ * @param {Chart} chart - the chart to remove the box from
+ * @param {Object} layoutItem - the item to remove from the layout
+ */
+ removeBox: function(chart, layoutItem) {
+ var index = chart.boxes? chart.boxes.indexOf(layoutItem) : -1;
+ if (index !== -1) {
+ chart.boxes.splice(index, 1);
+ }
+ },
+
+ /**
+ * Sets (or updates) options on the given `item`.
+ * @param {Chart} chart - the chart in which the item lives (or will be added to)
+ * @param {Object} item - the item to configure with the given options
+ * @param {Object} options - the new item options.
+ */
+ configure: function(chart, item, options) {
+ var props = ['fullWidth', 'position', 'weight'];
+ var ilen = props.length;
+ var i = 0;
+ var prop;
+
+ for (; i tickWidth && labelRotation < tickOpts.maxRotation) {
+ var angleRadians = helpers.toRadians(labelRotation);
+ cosRotation = Math.cos(angleRadians);
+ sinRotation = Math.sin(angleRadians);
+
+ if (sinRotation * originalLabelWidth > me.maxHeight) {
+ // go back one step
+ labelRotation--;
+ break;
+ }
+
+ labelRotation++;
+ labelWidth = cosRotation * originalLabelWidth;
+ }
+ }
+
+ me.labelRotation = labelRotation;
+ },
+ afterCalculateTickRotation: function() {
+ helpers.callback(this.options.afterCalculateTickRotation, [this]);
+ },
+
+ //
+
+ beforeFit: function() {
+ helpers.callback(this.options.beforeFit, [this]);
+ },
+ fit: function() {
+ var me = this;
+ // Reset
+ var minSize = me.minSize = {
+ width: 0,
+ height: 0
+ };
+
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+ var scaleLabelOpts = opts.scaleLabel;
+ var gridLineOpts = opts.gridLines;
+ var display = opts.display;
+ var isHorizontal = me.isHorizontal();
+
+ var tickFont = parseFontOptions(tickOpts);
+ var scaleLabelFontSize = parseFontOptions(scaleLabelOpts).size * 1.5;
+ var tickMarkLength = opts.gridLines.tickMarkLength;
+
+ // Width
+ if (isHorizontal) {
+ // subtract the margins to line up with the chartArea if we are a full width scale
+ minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
+ } else {
+ minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+ }
+
+ // height
+ if (isHorizontal) {
+ minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+ } else {
+ minSize.height = me.maxHeight; // fill all the height
+ }
+
+ // Are we showing a title for the scale?
+ if (scaleLabelOpts.display && display) {
+ if (isHorizontal) {
+ minSize.height += scaleLabelFontSize;
+ } else {
+ minSize.width += scaleLabelFontSize;
+ }
+ }
+
+ // Don't bother fitting the ticks if we are not showing them
+ if (tickOpts.display && display) {
+ var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, me.ticks, me.longestTextCache);
+ var tallestLabelHeightInLines = helpers.numberOfLabelLines(me.ticks);
+ var lineSpace = tickFont.size * 0.5;
+
+ if (isHorizontal) {
+ // A horizontal axis is more constrained by the height.
+ me.longestLabelWidth = largestTextWidth;
+
+ var angleRadians = helpers.toRadians(me.labelRotation);
+ var cosRotation = Math.cos(angleRadians);
+ var sinRotation = Math.sin(angleRadians);
+
+ // TODO - improve this calculation
+ var labelHeight = (sinRotation * largestTextWidth)
+ + (tickFont.size * tallestLabelHeightInLines)
+ + (lineSpace * tallestLabelHeightInLines);
+
+ minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight);
+ me.ctx.font = tickFont.font;
+
+ var firstTick = me.ticks[0];
+ var firstLabelWidth = computeTextSize(me.ctx, firstTick, tickFont.font);
+
+ var lastTick = me.ticks[me.ticks.length - 1];
+ var lastLabelWidth = computeTextSize(me.ctx, lastTick, tickFont.font);
+
+ // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
+ // by the font height
+ if (me.labelRotation !== 0) {
+ me.paddingLeft = opts.position === 'bottom'? (cosRotation * firstLabelWidth) + 3: (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
+ me.paddingRight = opts.position === 'bottom'? (cosRotation * lineSpace) + 3: (cosRotation * lastLabelWidth) + 3;
+ } else {
+ me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
+ me.paddingRight = lastLabelWidth / 2 + 3;
+ }
+ } else {
+ // A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
+ // Account for padding
+
+ if (tickOpts.mirror) {
+ largestTextWidth = 0;
+ } else {
+ largestTextWidth += me.options.ticks.padding;
+ }
+ minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
+ me.paddingTop = tickFont.size / 2;
+ me.paddingBottom = tickFont.size / 2;
+ }
+ }
+
+ me.handleMargins();
+
+ me.width = minSize.width;
+ me.height = minSize.height;
+ },
+
+ /**
+ * Handle margins and padding interactions
+ * @private
+ */
+ handleMargins: function() {
+ var me = this;
+ if (me.margins) {
+ me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
+ me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
+ me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
+ me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
+ }
+ },
+
+ afterFit: function() {
+ helpers.callback(this.options.afterFit, [this]);
+ },
+
+ // Shared Methods
+ isHorizontal: function() {
+ return this.options.position === 'top' || this.options.position === 'bottom';
+ },
+ isFullWidth: function() {
+ return (this.options.fullWidth);
+ },
+
+ // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
+ getRightValue: function(rawValue) {
+ // Null and undefined values first
+ if (rawValue === null || typeof(rawValue) === 'undefined') {
+ return NaN;
+ }
+ // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
+ if (typeof(rawValue) === 'number' && !isFinite(rawValue)) {
+ return NaN;
+ }
+ // If it is in fact an object, dive in one more level
+ if (typeof(rawValue) === 'object') {
+ if ((rawValue instanceof Date) || (rawValue.isValid)) {
+ return rawValue;
+ }
+ return this.getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
+ }
+
+ // Value is good, return it
+ return rawValue;
+ },
+
+ // Used to get the value to display in the tooltip for the data at the given index
+ // function getLabelForIndex(index, datasetIndex)
+ getLabelForIndex: helpers.noop,
+
+ // Used to get data value locations. Value can either be an index or a numerical value
+ getPixelForValue: helpers.noop,
+
+ // Used to get the data value from a given pixel. This is the inverse of getPixelForValue
+ getValueForPixel: helpers.noop,
+
+ // Used for tick location, should
+ getPixelForTick: function(index, includeOffset) {
+ var me = this;
+ if (me.isHorizontal()) {
+ var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+ var tickWidth = innerWidth / Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+ var pixel = (tickWidth * index) + me.paddingLeft;
+
+ if (includeOffset) {
+ pixel += tickWidth / 2;
+ }
+
+ var finalVal = me.left + Math.round(pixel);
+ finalVal += me.isFullWidth() ? me.margins.left : 0;
+ return finalVal;
+ }
+ var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
+ return me.top + (index * (innerHeight / (me.ticks.length - 1)));
+ },
+
+ // Utility for getting the pixel location of a percentage of scale
+ getPixelForDecimal: function(decimal /* , includeOffset*/) {
+ var me = this;
+ if (me.isHorizontal()) {
+ var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+ var valueOffset = (innerWidth * decimal) + me.paddingLeft;
+
+ var finalVal = me.left + Math.round(valueOffset);
+ finalVal += me.isFullWidth() ? me.margins.left : 0;
+ return finalVal;
+ }
+ return me.top + (decimal * me.height);
+ },
+
+ getBasePixel: function() {
+ return this.getPixelForValue(this.getBaseValue());
+ },
+
+ getBaseValue: function() {
+ var me = this;
+ var min = me.min;
+ var max = me.max;
+
+ return me.beginAtZero ? 0:
+ min < 0 && max < 0? max :
+ min > 0 && max > 0? min :
+ 0;
+ },
+
+ // Actually draw the scale on the canvas
+ // @param {rectangle} chartArea : the area of the chart to draw full grid lines on
+ draw: function(chartArea) {
+ var me = this;
+ var options = me.options;
+ if (!options.display) {
+ return;
+ }
+
+ var context = me.ctx;
+ var globalDefaults = Chart.defaults.global;
+ var optionTicks = options.ticks;
+ var gridLines = options.gridLines;
+ var scaleLabel = options.scaleLabel;
+
+ var isRotated = me.labelRotation !== 0;
+ var skipRatio;
+ var useAutoskipper = optionTicks.autoSkip;
+ var isHorizontal = me.isHorizontal();
+
+ // figure out the maximum number of gridlines to show
+ var maxTicks;
+ if (optionTicks.maxTicksLimit) {
+ maxTicks = optionTicks.maxTicksLimit;
+ }
+
+ var tickFontColor = helpers.getValueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
+ var tickFont = parseFontOptions(optionTicks);
+
+ var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
+
+ var scaleLabelFontColor = helpers.getValueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
+ var scaleLabelFont = parseFontOptions(scaleLabel);
+
+ var labelRotationRadians = helpers.toRadians(me.labelRotation);
+ var cosRotation = Math.cos(labelRotationRadians);
+ var longestRotatedLabel = me.longestLabelWidth * cosRotation;
+
+ // Make sure we draw text in the correct color and font
+ context.fillStyle = tickFontColor;
+
+ var itemsToDraw = [];
+
+ if (isHorizontal) {
+ skipRatio = false;
+
+ if ((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length > (me.width - (me.paddingLeft + me.paddingRight))) {
+ skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length) / (me.width - (me.paddingLeft + me.paddingRight)));
+ }
+
+ // if they defined a max number of optionTicks,
+ // increase skipRatio until that number is met
+ if (maxTicks && me.ticks.length > maxTicks) {
+ while (!skipRatio || me.ticks.length / (skipRatio || 1) > maxTicks) {
+ if (!skipRatio) {
+ skipRatio = 1;
+ }
+ skipRatio += 1;
+ }
+ }
+
+ if (!useAutoskipper) {
+ skipRatio = false;
+ }
+ }
+
+
+ var xTickStart = options.position === 'right' ? me.left : me.right - tl;
+ var xTickEnd = options.position === 'right' ? me.left + tl : me.right;
+ var yTickStart = options.position === 'bottom' ? me.top : me.bottom - tl;
+ var yTickEnd = options.position === 'bottom' ? me.top + tl : me.bottom;
+
+ helpers.each(me.ticks, function(label, index) {
+ // If the callback returned a null or undefined value, do not draw this line
+ if (label === undefined || label === null) {
+ return;
+ }
+
+ var isLastTick = me.ticks.length === index + 1;
+
+ // Since we always show the last tick,we need may need to hide the last shown one before
+ var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio >= me.ticks.length);
+ if (shouldSkip && !isLastTick || (label === undefined || label === null)) {
+ return;
+ }
+
+ var lineWidth, lineColor, borderDash, borderDashOffset;
+ if (index === (typeof me.zeroLineIndex !== 'undefined' ? me.zeroLineIndex : 0)) {
+ // Draw the first index specially
+ lineWidth = gridLines.zeroLineWidth;
+ lineColor = gridLines.zeroLineColor;
+ borderDash = gridLines.zeroLineBorderDash;
+ borderDashOffset = gridLines.zeroLineBorderDashOffset;
+ } else {
+ lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, index);
+ lineColor = helpers.getValueAtIndexOrDefault(gridLines.color, index);
+ borderDash = helpers.getValueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
+ borderDashOffset = helpers.getValueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
+ }
+
+ // Common properties
+ var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
+ var textAlign = 'middle';
+ var textBaseline = 'middle';
+
+ if (isHorizontal) {
+
+ if (options.position === 'bottom') {
+ // bottom
+ textBaseline = !isRotated? 'top':'middle';
+ textAlign = !isRotated? 'center': 'right';
+ labelY = me.top + tl;
+ } else {
+ // top
+ textBaseline = !isRotated? 'bottom':'middle';
+ textAlign = !isRotated? 'center': 'left';
+ labelY = me.bottom - tl;
+ }
+
+ var xLineValue = me.getPixelForTick(index) + helpers.aliasPixel(lineWidth); // xvalues for grid lines
+ labelX = me.getPixelForTick(index, gridLines.offsetGridLines) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
+
+ tx1 = tx2 = x1 = x2 = xLineValue;
+ ty1 = yTickStart;
+ ty2 = yTickEnd;
+ y1 = chartArea.top;
+ y2 = chartArea.bottom;
+ } else {
+ var isLeft = options.position === 'left';
+ var tickPadding = optionTicks.padding;
+ var labelXOffset;
+
+ if (optionTicks.mirror) {
+ textAlign = isLeft ? 'left' : 'right';
+ labelXOffset = tickPadding;
+ } else {
+ textAlign = isLeft ? 'right' : 'left';
+ labelXOffset = tl + tickPadding;
+ }
+
+ labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
+
+ var yLineValue = me.getPixelForTick(index); // xvalues for grid lines
+ yLineValue += helpers.aliasPixel(lineWidth);
+ labelY = me.getPixelForTick(index, gridLines.offsetGridLines);
+
+ tx1 = xTickStart;
+ tx2 = xTickEnd;
+ x1 = chartArea.left;
+ x2 = chartArea.right;
+ ty1 = ty2 = y1 = y2 = yLineValue;
+ }
+
+ itemsToDraw.push({
+ tx1: tx1,
+ ty1: ty1,
+ tx2: tx2,
+ ty2: ty2,
+ x1: x1,
+ y1: y1,
+ x2: x2,
+ y2: y2,
+ labelX: labelX,
+ labelY: labelY,
+ glWidth: lineWidth,
+ glColor: lineColor,
+ glBorderDash: borderDash,
+ glBorderDashOffset: borderDashOffset,
+ rotation: -1 * labelRotationRadians,
+ label: label,
+ textBaseline: textBaseline,
+ textAlign: textAlign
+ });
+ });
+
+ // Draw all of the tick labels, tick marks, and grid lines at the correct places
+ helpers.each(itemsToDraw, function(itemToDraw) {
+ if (gridLines.display) {
+ context.save();
+ context.lineWidth = itemToDraw.glWidth;
+ context.strokeStyle = itemToDraw.glColor;
+ if (context.setLineDash) {
+ context.setLineDash(itemToDraw.glBorderDash);
+ context.lineDashOffset = itemToDraw.glBorderDashOffset;
+ }
+
+ context.beginPath();
+
+ if (gridLines.drawTicks) {
+ context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
+ context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
+ }
+
+ if (gridLines.drawOnChartArea) {
+ context.moveTo(itemToDraw.x1, itemToDraw.y1);
+ context.lineTo(itemToDraw.x2, itemToDraw.y2);
+ }
+
+ context.stroke();
+ context.restore();
+ }
+
+ if (optionTicks.display) {
+ context.save();
+ context.translate(itemToDraw.labelX, itemToDraw.labelY);
+ context.rotate(itemToDraw.rotation);
+ context.font = tickFont.font;
+ context.textBaseline = itemToDraw.textBaseline;
+ context.textAlign = itemToDraw.textAlign;
+
+ var label = itemToDraw.label;
+ if (helpers.isArray(label)) {
+ for (var i = 0, y = 0; i < label.length; ++i) {
+ // We just make sure the multiline element is a string here..
+ context.fillText('' + label[i], 0, y);
+ // apply same lineSpacing as calculated @ L#320
+ y += (tickFont.size * 1.5);
+ }
+ } else {
+ context.fillText(label, 0, 0);
+ }
+ context.restore();
+ }
+ });
+
+ if (scaleLabel.display) {
+ // Draw the scale label
+ var scaleLabelX;
+ var scaleLabelY;
+ var rotation = 0;
+
+ if (isHorizontal) {
+ scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
+ scaleLabelY = options.position === 'bottom' ? me.bottom - (scaleLabelFont.size / 2) : me.top + (scaleLabelFont.size / 2);
+ } else {
+ var isLeft = options.position === 'left';
+ scaleLabelX = isLeft ? me.left + (scaleLabelFont.size / 2) : me.right - (scaleLabelFont.size / 2);
+ scaleLabelY = me.top + ((me.bottom - me.top) / 2);
+ rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
+ }
+
+ context.save();
+ context.translate(scaleLabelX, scaleLabelY);
+ context.rotate(rotation);
+ context.textAlign = 'center';
+ context.textBaseline = 'middle';
+ context.fillStyle = scaleLabelFontColor; // render in correct colour
+ context.font = scaleLabelFont.font;
+ context.fillText(scaleLabel.labelString, 0, 0);
+ context.restore();
+ }
+
+ if (gridLines.drawBorder) {
+ // Draw the line at the edge of the axis
+ context.lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, 0);
+ context.strokeStyle = helpers.getValueAtIndexOrDefault(gridLines.color, 0);
+ var x1 = me.left,
+ x2 = me.right,
+ y1 = me.top,
+ y2 = me.bottom;
+
+ var aliasPixel = helpers.aliasPixel(context.lineWidth);
+ if (isHorizontal) {
+ y1 = y2 = options.position === 'top' ? me.bottom : me.top;
+ y1 += aliasPixel;
+ y2 += aliasPixel;
+ } else {
+ x1 = x2 = options.position === 'left' ? me.right : me.left;
+ x1 += aliasPixel;
+ x2 += aliasPixel;
+ }
+
+ context.beginPath();
+ context.moveTo(x1, y1);
+ context.lineTo(x2, y2);
+ context.stroke();
+ }
+ }
+ });
+};
+
+},{}],32:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ Chart.scaleService = {
+ // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
+ // use the new chart options to grab the correct scale
+ constructors: {},
+ // Use a registration function so that we can move to an ES6 map when we no longer need to support
+ // old browsers
+
+ // Scale config defaults
+ defaults: {},
+ registerScaleType: function(type, scaleConstructor, defaults) {
+ this.constructors[type] = scaleConstructor;
+ this.defaults[type] = helpers.clone(defaults);
+ },
+ getScaleConstructor: function(type) {
+ return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
+ },
+ getScaleDefaults: function(type) {
+ // Return the scale defaults merged with the global settings so that we always use the latest ones
+ return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
+ },
+ updateScaleDefaults: function(type, additions) {
+ var defaults = this.defaults;
+ if (defaults.hasOwnProperty(type)) {
+ defaults[type] = helpers.extend(defaults[type], additions);
+ }
+ },
+ addScalesToLayout: function(chart) {
+ // Adds each scale to the chart.boxes array to be sized accordingly
+ helpers.each(chart.scales, function(scale) {
+ // Set ILayoutItem parameters for backwards compatibility
+ scale.fullWidth = scale.options.fullWidth;
+ scale.position = scale.options.position;
+ scale.weight = scale.options.weight;
+ Chart.layoutService.addBox(chart, scale);
+ });
+ }
+ };
+};
+
+},{}],33:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ /**
+ * Namespace to hold static tick generation functions
+ * @namespace Chart.Ticks
+ */
+ Chart.Ticks = {
+ /**
+ * Namespace to hold generators for different types of ticks
+ * @namespace Chart.Ticks.generators
+ */
+ generators: {
+ /**
+ * Interface for the options provided to the numeric tick generator
+ * @interface INumericTickGenerationOptions
+ */
+ /**
+ * The maximum number of ticks to display
+ * @name INumericTickGenerationOptions#maxTicks
+ * @type Number
+ */
+ /**
+ * The distance between each tick.
+ * @name INumericTickGenerationOptions#stepSize
+ * @type Number
+ * @optional
+ */
+ /**
+ * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum
+ * @name INumericTickGenerationOptions#min
+ * @type Number
+ * @optional
+ */
+ /**
+ * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum
+ * @name INumericTickGenerationOptions#max
+ * @type Number
+ * @optional
+ */
+
+ /**
+ * Generate a set of linear ticks
+ * @method Chart.Ticks.generators.linear
+ * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
+ * @param dataRange {IRange} the range of the data
+ * @returns {Array} array of tick values
+ */
+ linear: function(generationOptions, dataRange) {
+ var ticks = [];
+ // To get a "nice" value for the tick spacing, we will use the appropriately named
+ // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
+ // for details.
+
+ var spacing;
+ if (generationOptions.stepSize && generationOptions.stepSize > 0) {
+ spacing = generationOptions.stepSize;
+ } else {
+ var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
+ spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
+ }
+ var niceMin = Math.floor(dataRange.min / spacing) * spacing;
+ var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
+
+ // If min, max and stepSize is set and they make an evenly spaced scale use it.
+ if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
+ // If very close to our whole number, use it.
+ if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
+ niceMin = generationOptions.min;
+ niceMax = generationOptions.max;
+ }
+ }
+
+ var numSpaces = (niceMax - niceMin) / spacing;
+ // If very close to our rounded value, use it.
+ if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
+ numSpaces = Math.round(numSpaces);
+ } else {
+ numSpaces = Math.ceil(numSpaces);
+ }
+
+ // Put the values into the ticks array
+ ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
+ for (var j = 1; j < numSpaces; ++j) {
+ ticks.push(niceMin + (j * spacing));
+ }
+ ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
+
+ return ticks;
+ },
+
+ /**
+ * Generate a set of logarithmic ticks
+ * @method Chart.Ticks.generators.logarithmic
+ * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
+ * @param dataRange {IRange} the range of the data
+ * @returns {Array} array of tick values
+ */
+ logarithmic: function(generationOptions, dataRange) {
+ var ticks = [];
+ var getValueOrDefault = helpers.getValueOrDefault;
+
+ // Figure out what the max number of ticks we can support it is based on the size of
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+ // the graph
+ var tickVal = getValueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
+
+ var endExp = Math.floor(helpers.log10(dataRange.max));
+ var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
+ var exp;
+ var significand;
+
+ if (tickVal === 0) {
+ exp = Math.floor(helpers.log10(dataRange.minNotZero));
+ significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
+
+ ticks.push(tickVal);
+ tickVal = significand * Math.pow(10, exp);
+ } else {
+ exp = Math.floor(helpers.log10(tickVal));
+ significand = Math.floor(tickVal / Math.pow(10, exp));
+ }
+
+ do {
+ ticks.push(tickVal);
+
+ ++significand;
+ if (significand === 10) {
+ significand = 1;
+ ++exp;
+ }
+
+ tickVal = significand * Math.pow(10, exp);
+ } while (exp < endExp || (exp === endExp && significand < endSignificand));
+
+ var lastTick = getValueOrDefault(generationOptions.max, tickVal);
+ ticks.push(lastTick);
+
+ return ticks;
+ }
+ },
+
+ /**
+ * Namespace to hold formatters for different types of ticks
+ * @namespace Chart.Ticks.formatters
+ */
+ formatters: {
+ /**
+ * Formatter for value labels
+ * @method Chart.Ticks.formatters.values
+ * @param value the value to display
+ * @return {String|Array} the label to display
+ */
+ values: function(value) {
+ return helpers.isArray(value) ? value : '' + value;
+ },
+
+ /**
+ * Formatter for linear numeric ticks
+ * @method Chart.Ticks.formatters.linear
+ * @param tickValue {Number} the value to be formatted
+ * @param index {Number} the position of the tickValue parameter in the ticks array
+ * @param ticks {Array} the list of ticks being converted
+ * @return {String} string representation of the tickValue parameter
+ */
+ linear: function(tickValue, index, ticks) {
+ // If we have lots of ticks, don't use the ones
+ var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
+
+ // If we have a number like 2.5 as the delta, figure out how many decimal places we need
+ if (Math.abs(delta) > 1) {
+ if (tickValue !== Math.floor(tickValue)) {
+ // not an integer
+ delta = tickValue - Math.floor(tickValue);
+ }
+ }
+
+ var logDelta = helpers.log10(Math.abs(delta));
+ var tickString = '';
+
+ if (tickValue !== 0) {
+ var numDecimal = -1 * Math.floor(logDelta);
+ numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
+ tickString = tickValue.toFixed(numDecimal);
+ } else {
+ tickString = '0'; // never show decimal places for 0
+ }
+
+ return tickString;
+ },
+
+ logarithmic: function(tickValue, index, ticks) {
+ var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));
+
+ if (tickValue === 0) {
+ return '0';
+ } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
+ return tickValue.toExponential();
+ }
+ return '';
+ }
+ }
+ };
+};
+
+},{}],34:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ /**
+ * Helper method to merge the opacity into a color
+ */
+ function mergeOpacity(colorString, opacity) {
+ var color = helpers.color(colorString);
+ return color.alpha(opacity * color.alpha()).rgbaString();
+ }
+
+ Chart.defaults.global.tooltips = {
+ enabled: true,
+ custom: null,
+ mode: 'nearest',
+ position: 'average',
+ intersect: true,
+ backgroundColor: 'rgba(0,0,0,0.8)',
+ titleFontStyle: 'bold',
+ titleSpacing: 2,
+ titleMarginBottom: 6,
+ titleFontColor: '#fff',
+ titleAlign: 'left',
+ bodySpacing: 2,
+ bodyFontColor: '#fff',
+ bodyAlign: 'left',
+ footerFontStyle: 'bold',
+ footerSpacing: 2,
+ footerMarginTop: 6,
+ footerFontColor: '#fff',
+ footerAlign: 'left',
+ yPadding: 6,
+ xPadding: 6,
+ caretPadding: 2,
+ caretSize: 5,
+ cornerRadius: 6,
+ multiKeyBackground: '#fff',
+ displayColors: true,
+ borderColor: 'rgba(0,0,0,0)',
+ borderWidth: 0,
+ callbacks: {
+ // Args are: (tooltipItems, data)
+ beforeTitle: helpers.noop,
+ title: function(tooltipItems, data) {
+ // Pick first xLabel for now
+ var title = '';
+ var labels = data.labels;
+ var labelCount = labels ? labels.length : 0;
+
+ if (tooltipItems.length > 0) {
+ var item = tooltipItems[0];
+
+ if (item.xLabel) {
+ title = item.xLabel;
+ } else if (labelCount > 0 && item.index < labelCount) {
+ title = labels[item.index];
+ }
+ }
+
+ return title;
+ },
+ afterTitle: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ beforeBody: helpers.noop,
+
+ // Args are: (tooltipItem, data)
+ beforeLabel: helpers.noop,
+ label: function(tooltipItem, data) {
+ var label = data.datasets[tooltipItem.datasetIndex].label || '';
+
+ if (label) {
+ label += ': ';
+ }
+ label += tooltipItem.yLabel;
+ return label;
+ },
+ labelColor: function(tooltipItem, chart) {
+ var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
+ var activeElement = meta.data[tooltipItem.index];
+ var view = activeElement._view;
+ return {
+ borderColor: view.borderColor,
+ backgroundColor: view.backgroundColor
+ };
+ },
+ afterLabel: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ afterBody: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ beforeFooter: helpers.noop,
+ footer: helpers.noop,
+ afterFooter: helpers.noop
+ }
+ };
+
+ // Helper to push or concat based on if the 2nd parameter is an array or not
+ function pushOrConcat(base, toPush) {
+ if (toPush) {
+ if (helpers.isArray(toPush)) {
+ // base = base.concat(toPush);
+ Array.prototype.push.apply(base, toPush);
+ } else {
+ base.push(toPush);
+ }
+ }
+
+ return base;
+ }
+
+ // Private helper to create a tooltip item model
+ // @param element : the chart element (point, arc, bar) to create the tooltip item for
+ // @return : new tooltip item
+ function createTooltipItem(element) {
+ var xScale = element._xScale;
+ var yScale = element._yScale || element._scale; // handle radar || polarArea charts
+ var index = element._index,
+ datasetIndex = element._datasetIndex;
+
+ return {
+ xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
+ yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
+ index: index,
+ datasetIndex: datasetIndex,
+ x: element._model.x,
+ y: element._model.y
+ };
+ }
+
+ /**
+ * Helper to get the reset model for the tooltip
+ * @param tooltipOpts {Object} the tooltip options
+ */
+ function getBaseModel(tooltipOpts) {
+ var globalDefaults = Chart.defaults.global;
+ var getValueOrDefault = helpers.getValueOrDefault;
+
+ return {
+ // Positioning
+ xPadding: tooltipOpts.xPadding,
+ yPadding: tooltipOpts.yPadding,
+ xAlign: tooltipOpts.xAlign,
+ yAlign: tooltipOpts.yAlign,
+
+ // Body
+ bodyFontColor: tooltipOpts.bodyFontColor,
+ _bodyFontFamily: getValueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
+ _bodyFontStyle: getValueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
+ _bodyAlign: tooltipOpts.bodyAlign,
+ bodyFontSize: getValueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
+ bodySpacing: tooltipOpts.bodySpacing,
+
+ // Title
+ titleFontColor: tooltipOpts.titleFontColor,
+ _titleFontFamily: getValueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
+ _titleFontStyle: getValueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
+ titleFontSize: getValueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
+ _titleAlign: tooltipOpts.titleAlign,
+ titleSpacing: tooltipOpts.titleSpacing,
+ titleMarginBottom: tooltipOpts.titleMarginBottom,
+
+ // Footer
+ footerFontColor: tooltipOpts.footerFontColor,
+ _footerFontFamily: getValueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
+ _footerFontStyle: getValueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
+ footerFontSize: getValueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
+ _footerAlign: tooltipOpts.footerAlign,
+ footerSpacing: tooltipOpts.footerSpacing,
+ footerMarginTop: tooltipOpts.footerMarginTop,
+
+ // Appearance
+ caretSize: tooltipOpts.caretSize,
+ cornerRadius: tooltipOpts.cornerRadius,
+ backgroundColor: tooltipOpts.backgroundColor,
+ opacity: 0,
+ legendColorBackground: tooltipOpts.multiKeyBackground,
+ displayColors: tooltipOpts.displayColors,
+ borderColor: tooltipOpts.borderColor,
+ borderWidth: tooltipOpts.borderWidth
+ };
+ }
+
+ /**
+ * Get the size of the tooltip
+ */
+ function getTooltipSize(tooltip, model) {
+ var ctx = tooltip._chart.ctx;
+
+ var height = model.yPadding * 2; // Tooltip Padding
+ var width = 0;
+
+ // Count of all lines in the body
+ var body = model.body;
+ var combinedBodyLength = body.reduce(function(count, bodyItem) {
+ return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
+ }, 0);
+ combinedBodyLength += model.beforeBody.length + model.afterBody.length;
+
+ var titleLineCount = model.title.length;
+ var footerLineCount = model.footer.length;
+ var titleFontSize = model.titleFontSize,
+ bodyFontSize = model.bodyFontSize,
+ footerFontSize = model.footerFontSize;
+
+ height += titleLineCount * titleFontSize; // Title Lines
+ height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
+ height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
+ height += combinedBodyLength * bodyFontSize; // Body Lines
+ height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
+ height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
+ height += footerLineCount * (footerFontSize); // Footer Lines
+ height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
+
+ // Title width
+ var widthPadding = 0;
+ var maxLineWidth = function(line) {
+ width = Math.max(width, ctx.measureText(line).width + widthPadding);
+ };
+
+ ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
+ helpers.each(model.title, maxLineWidth);
+
+ // Body width
+ ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
+ helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
+
+ // Body lines may include some extra width due to the color box
+ widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
+ helpers.each(body, function(bodyItem) {
+ helpers.each(bodyItem.before, maxLineWidth);
+ helpers.each(bodyItem.lines, maxLineWidth);
+ helpers.each(bodyItem.after, maxLineWidth);
+ });
+
+ // Reset back to 0
+ widthPadding = 0;
+
+ // Footer width
+ ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
+ helpers.each(model.footer, maxLineWidth);
+
+ // Add padding
+ width += 2 * model.xPadding;
+
+ return {
+ width: width,
+ height: height
+ };
+ }
+
+ /**
+ * Helper to get the alignment of a tooltip given the size
+ */
+ function determineAlignment(tooltip, size) {
+ var model = tooltip._model;
+ var chart = tooltip._chart;
+ var chartArea = tooltip._chart.chartArea;
+ var xAlign = 'center';
+ var yAlign = 'center';
+
+ if (model.y < size.height) {
+ yAlign = 'top';
+ } else if (model.y > (chart.height - size.height)) {
+ yAlign = 'bottom';
+ }
+
+ var lf, rf; // functions to determine left, right alignment
+ var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
+ var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
+ var midX = (chartArea.left + chartArea.right) / 2;
+ var midY = (chartArea.top + chartArea.bottom) / 2;
+
+ if (yAlign === 'center') {
+ lf = function(x) {
+ return x <= midX;
+ };
+ rf = function(x) {
+ return x > midX;
+ };
+ } else {
+ lf = function(x) {
+ return x <= (size.width / 2);
+ };
+ rf = function(x) {
+ return x >= (chart.width - (size.width / 2));
+ };
+ }
+
+ olf = function(x) {
+ return x + size.width > chart.width;
+ };
+ orf = function(x) {
+ return x - size.width < 0;
+ };
+ yf = function(y) {
+ return y <= midY ? 'top' : 'bottom';
+ };
+
+ if (lf(model.x)) {
+ xAlign = 'left';
+
+ // Is tooltip too wide and goes over the right side of the chart.?
+ if (olf(model.x)) {
+ xAlign = 'center';
+ yAlign = yf(model.y);
+ }
+ } else if (rf(model.x)) {
+ xAlign = 'right';
+
+ // Is tooltip too wide and goes outside left edge of canvas?
+ if (orf(model.x)) {
+ xAlign = 'center';
+ yAlign = yf(model.y);
+ }
+ }
+
+ var opts = tooltip._options;
+ return {
+ xAlign: opts.xAlign ? opts.xAlign : xAlign,
+ yAlign: opts.yAlign ? opts.yAlign : yAlign
+ };
+ }
+
+ /**
+ * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
+ */
+ function getBackgroundPoint(vm, size, alignment) {
+ // Background Position
+ var x = vm.x;
+ var y = vm.y;
+
+ var caretSize = vm.caretSize,
+ caretPadding = vm.caretPadding,
+ cornerRadius = vm.cornerRadius,
+ xAlign = alignment.xAlign,
+ yAlign = alignment.yAlign,
+ paddingAndSize = caretSize + caretPadding,
+ radiusAndPadding = cornerRadius + caretPadding;
+
+ if (xAlign === 'right') {
+ x -= size.width;
+ } else if (xAlign === 'center') {
+ x -= (size.width / 2);
+ }
+
+ if (yAlign === 'top') {
+ y += paddingAndSize;
+ } else if (yAlign === 'bottom') {
+ y -= size.height + paddingAndSize;
+ } else {
+ y -= (size.height / 2);
+ }
+
+ if (yAlign === 'center') {
+ if (xAlign === 'left') {
+ x += paddingAndSize;
+ } else if (xAlign === 'right') {
+ x -= paddingAndSize;
+ }
+ } else if (xAlign === 'left') {
+ x -= radiusAndPadding;
+ } else if (xAlign === 'right') {
+ x += radiusAndPadding;
+ }
+
+ return {
+ x: x,
+ y: y
+ };
+ }
+
+ Chart.Tooltip = Chart.Element.extend({
+ initialize: function() {
+ this._model = getBaseModel(this._options);
+ },
+
+ // Get the title
+ // Args are: (tooltipItem, data)
+ getTitle: function() {
+ var me = this;
+ var opts = me._options;
+ var callbacks = opts.callbacks;
+
+ var beforeTitle = callbacks.beforeTitle.apply(me, arguments),
+ title = callbacks.title.apply(me, arguments),
+ afterTitle = callbacks.afterTitle.apply(me, arguments);
+
+ var lines = [];
+ lines = pushOrConcat(lines, beforeTitle);
+ lines = pushOrConcat(lines, title);
+ lines = pushOrConcat(lines, afterTitle);
+
+ return lines;
+ },
+
+ // Args are: (tooltipItem, data)
+ getBeforeBody: function() {
+ var lines = this._options.callbacks.beforeBody.apply(this, arguments);
+ return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
+ },
+
+ // Args are: (tooltipItem, data)
+ getBody: function(tooltipItems, data) {
+ var me = this;
+ var callbacks = me._options.callbacks;
+ var bodyItems = [];
+
+ helpers.each(tooltipItems, function(tooltipItem) {
+ var bodyItem = {
+ before: [],
+ lines: [],
+ after: []
+ };
+ pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
+ pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
+ pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
+
+ bodyItems.push(bodyItem);
+ });
+
+ return bodyItems;
+ },
+
+ // Args are: (tooltipItem, data)
+ getAfterBody: function() {
+ var lines = this._options.callbacks.afterBody.apply(this, arguments);
+ return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
+ },
+
+ // Get the footer and beforeFooter and afterFooter lines
+ // Args are: (tooltipItem, data)
+ getFooter: function() {
+ var me = this;
+ var callbacks = me._options.callbacks;
+
+ var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
+ var footer = callbacks.footer.apply(me, arguments);
+ var afterFooter = callbacks.afterFooter.apply(me, arguments);
+
+ var lines = [];
+ lines = pushOrConcat(lines, beforeFooter);
+ lines = pushOrConcat(lines, footer);
+ lines = pushOrConcat(lines, afterFooter);
+
+ return lines;
+ },
+
+ update: function(changed) {
+ var me = this;
+ var opts = me._options;
+
+ // Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
+ // that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
+ // which breaks any animations.
+ var existingModel = me._model;
+ var model = me._model = getBaseModel(opts);
+ var active = me._active;
+
+ var data = me._data;
+
+ // In the case where active.length === 0 we need to keep these at existing values for good animations
+ var alignment = {
+ xAlign: existingModel.xAlign,
+ yAlign: existingModel.yAlign
+ };
+ var backgroundPoint = {
+ x: existingModel.x,
+ y: existingModel.y
+ };
+ var tooltipSize = {
+ width: existingModel.width,
+ height: existingModel.height
+ };
+ var tooltipPosition = {
+ x: existingModel.caretX,
+ y: existingModel.caretY
+ };
+
+ var i, len;
+
+ if (active.length) {
+ model.opacity = 1;
+
+ var labelColors = [];
+ tooltipPosition = Chart.Tooltip.positioners[opts.position](active, me._eventPosition);
+
+ var tooltipItems = [];
+ for (i = 0, len = active.length; i < len; ++i) {
+ tooltipItems.push(createTooltipItem(active[i]));
+ }
+
+ // If the user provided a filter function, use it to modify the tooltip items
+ if (opts.filter) {
+ tooltipItems = tooltipItems.filter(function(a) {
+ return opts.filter(a, data);
+ });
+ }
+
+ // If the user provided a sorting function, use it to modify the tooltip items
+ if (opts.itemSort) {
+ tooltipItems = tooltipItems.sort(function(a, b) {
+ return opts.itemSort(a, b, data);
+ });
+ }
+
+ // Determine colors for boxes
+ helpers.each(tooltipItems, function(tooltipItem) {
+ labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
+ });
+
+ // Build the Text Lines
+ model.title = me.getTitle(tooltipItems, data);
+ model.beforeBody = me.getBeforeBody(tooltipItems, data);
+ model.body = me.getBody(tooltipItems, data);
+ model.afterBody = me.getAfterBody(tooltipItems, data);
+ model.footer = me.getFooter(tooltipItems, data);
+
+ // Initial positioning and colors
+ model.x = Math.round(tooltipPosition.x);
+ model.y = Math.round(tooltipPosition.y);
+ model.caretPadding = opts.caretPadding;
+ model.labelColors = labelColors;
+
+ // data points
+ model.dataPoints = tooltipItems;
+
+ // We need to determine alignment of the tooltip
+ tooltipSize = getTooltipSize(this, model);
+ alignment = determineAlignment(this, tooltipSize);
+ // Final Size and Position
+ backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment);
+ } else {
+ model.opacity = 0;
+ }
+
+ model.xAlign = alignment.xAlign;
+ model.yAlign = alignment.yAlign;
+ model.x = backgroundPoint.x;
+ model.y = backgroundPoint.y;
+ model.width = tooltipSize.width;
+ model.height = tooltipSize.height;
+
+ // Point where the caret on the tooltip points to
+ model.caretX = tooltipPosition.x;
+ model.caretY = tooltipPosition.y;
+
+ me._model = model;
+
+ if (changed && opts.custom) {
+ opts.custom.call(me, model);
+ }
+
+ return me;
+ },
+ drawCaret: function(tooltipPoint, size) {
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+ var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
+
+ ctx.lineTo(caretPosition.x1, caretPosition.y1);
+ ctx.lineTo(caretPosition.x2, caretPosition.y2);
+ ctx.lineTo(caretPosition.x3, caretPosition.y3);
+ },
+ getCaretPosition: function(tooltipPoint, size, vm) {
+ var x1, x2, x3;
+ var y1, y2, y3;
+ var caretSize = vm.caretSize;
+ var cornerRadius = vm.cornerRadius;
+ var xAlign = vm.xAlign,
+ yAlign = vm.yAlign;
+ var ptX = tooltipPoint.x,
+ ptY = tooltipPoint.y;
+ var width = size.width,
+ height = size.height;
+
+ if (yAlign === 'center') {
+ y2 = ptY + (height / 2);
+
+ if (xAlign === 'left') {
+ x1 = ptX;
+ x2 = x1 - caretSize;
+ x3 = x1;
+
+ y1 = y2 + caretSize;
+ y3 = y2 - caretSize;
+ } else {
+ x1 = ptX + width;
+ x2 = x1 + caretSize;
+ x3 = x1;
+
+ y1 = y2 - caretSize;
+ y3 = y2 + caretSize;
+ }
+ } else {
+ if (xAlign === 'left') {
+ x2 = ptX + cornerRadius + (caretSize);
+ x1 = x2 - caretSize;
+ x3 = x2 + caretSize;
+ } else if (xAlign === 'right') {
+ x2 = ptX + width - cornerRadius - caretSize;
+ x1 = x2 - caretSize;
+ x3 = x2 + caretSize;
+ } else {
+ x2 = ptX + (width / 2);
+ x1 = x2 - caretSize;
+ x3 = x2 + caretSize;
+ }
+ if (yAlign === 'top') {
+ y1 = ptY;
+ y2 = y1 - caretSize;
+ y3 = y1;
+ } else {
+ y1 = ptY + height;
+ y2 = y1 + caretSize;
+ y3 = y1;
+ // invert drawing order
+ var tmp = x3;
+ x3 = x1;
+ x1 = tmp;
+ }
+ }
+ return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
+ },
+ drawTitle: function(pt, vm, ctx, opacity) {
+ var title = vm.title;
+
+ if (title.length) {
+ ctx.textAlign = vm._titleAlign;
+ ctx.textBaseline = 'top';
+
+ var titleFontSize = vm.titleFontSize,
+ titleSpacing = vm.titleSpacing;
+
+ ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
+ ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+
+ var i, len;
+ for (i = 0, len = title.length; i < len; ++i) {
+ ctx.fillText(title[i], pt.x, pt.y);
+ pt.y += titleFontSize + titleSpacing; // Line Height and spacing
+
+ if (i + 1 === title.length) {
+ pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
+ }
+ }
+ }
+ },
+ drawBody: function(pt, vm, ctx, opacity) {
+ var bodyFontSize = vm.bodyFontSize;
+ var bodySpacing = vm.bodySpacing;
+ var body = vm.body;
+
+ ctx.textAlign = vm._bodyAlign;
+ ctx.textBaseline = 'top';
+
+ var textColor = mergeOpacity(vm.bodyFontColor, opacity);
+ ctx.fillStyle = textColor;
+ ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+
+ // Before Body
+ var xLinePadding = 0;
+ var fillLineOfText = function(line) {
+ ctx.fillText(line, pt.x + xLinePadding, pt.y);
+ pt.y += bodyFontSize + bodySpacing;
+ };
+
+ // Before body lines
+ helpers.each(vm.beforeBody, fillLineOfText);
+
+ var drawColorBoxes = vm.displayColors;
+ xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
+
+ // Draw body lines now
+ helpers.each(body, function(bodyItem, i) {
+ helpers.each(bodyItem.before, fillLineOfText);
+
+ helpers.each(bodyItem.lines, function(line) {
+ // Draw Legend-like boxes if needed
+ if (drawColorBoxes) {
+ // Fill a white rect so that colours merge nicely if the opacity is < 1
+ ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
+ ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
+
+ // Border
+ ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
+ ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
+
+ // Inner square
+ ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
+ ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
+
+ ctx.fillStyle = textColor;
+ }
+
+ fillLineOfText(line);
+ });
+
+ helpers.each(bodyItem.after, fillLineOfText);
+ });
+
+ // Reset back to 0 for after body
+ xLinePadding = 0;
+
+ // After body lines
+ helpers.each(vm.afterBody, fillLineOfText);
+ pt.y -= bodySpacing; // Remove last body spacing
+ },
+ drawFooter: function(pt, vm, ctx, opacity) {
+ var footer = vm.footer;
+
+ if (footer.length) {
+ pt.y += vm.footerMarginTop;
+
+ ctx.textAlign = vm._footerAlign;
+ ctx.textBaseline = 'top';
+
+ ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
+ ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
+
+ helpers.each(footer, function(line) {
+ ctx.fillText(line, pt.x, pt.y);
+ pt.y += vm.footerFontSize + vm.footerSpacing;
+ });
+ }
+ },
+ drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
+ ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
+ ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
+ ctx.lineWidth = vm.borderWidth;
+ var xAlign = vm.xAlign;
+ var yAlign = vm.yAlign;
+ var x = pt.x;
+ var y = pt.y;
+ var width = tooltipSize.width;
+ var height = tooltipSize.height;
+ var radius = vm.cornerRadius;
+
+ ctx.beginPath();
+ ctx.moveTo(x + radius, y);
+ if (yAlign === 'top') {
+ this.drawCaret(pt, tooltipSize);
+ }
+ ctx.lineTo(x + width - radius, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+ if (yAlign === 'center' && xAlign === 'right') {
+ this.drawCaret(pt, tooltipSize);
+ }
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+ if (yAlign === 'bottom') {
+ this.drawCaret(pt, tooltipSize);
+ }
+ ctx.lineTo(x + radius, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+ if (yAlign === 'center' && xAlign === 'left') {
+ this.drawCaret(pt, tooltipSize);
+ }
+ ctx.lineTo(x, y + radius);
+ ctx.quadraticCurveTo(x, y, x + radius, y);
+ ctx.closePath();
+
+ ctx.fill();
+
+ if (vm.borderWidth > 0) {
+ ctx.stroke();
+ }
+ },
+ draw: function() {
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+
+ if (vm.opacity === 0) {
+ return;
+ }
+
+ var tooltipSize = {
+ width: vm.width,
+ height: vm.height
+ };
+ var pt = {
+ x: vm.x,
+ y: vm.y
+ };
+
+ // IE11/Edge does not like very small opacities, so snap to 0
+ var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
+
+ // Truthy/falsey value for empty tooltip
+ var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
+
+ if (this._options.enabled && hasTooltipContent) {
+ // Draw Background
+ this.drawBackground(pt, vm, ctx, tooltipSize, opacity);
+
+ // Draw Title, Body, and Footer
+ pt.x += vm.xPadding;
+ pt.y += vm.yPadding;
+
+ // Titles
+ this.drawTitle(pt, vm, ctx, opacity);
+
+ // Body
+ this.drawBody(pt, vm, ctx, opacity);
+
+ // Footer
+ this.drawFooter(pt, vm, ctx, opacity);
+ }
+ },
+
+ /**
+ * Handle an event
+ * @private
+ * @param {IEvent} event - The event to handle
+ * @returns {Boolean} true if the tooltip changed
+ */
+ handleEvent: function(e) {
+ var me = this;
+ var options = me._options;
+ var changed = false;
+
+ me._lastActive = me._lastActive || [];
+
+ // Find Active Elements for tooltips
+ if (e.type === 'mouseout') {
+ me._active = [];
+ } else {
+ me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
+ }
+
+ // Remember Last Actives
+ changed = !helpers.arrayEquals(me._active, me._lastActive);
+
+ // If tooltip didn't change, do not handle the target event
+ if (!changed) {
+ return false;
+ }
+
+ me._lastActive = me._active;
+
+ if (options.enabled || options.custom) {
+ me._eventPosition = {
+ x: e.x,
+ y: e.y
+ };
+
+ var model = me._model;
+ me.update(true);
+ me.pivot();
+
+ // See if our tooltip position changed
+ changed |= (model.x !== me._model.x) || (model.y !== me._model.y);
+ }
+
+ return changed;
+ }
+ });
+
+ /**
+ * @namespace Chart.Tooltip.positioners
+ */
+ Chart.Tooltip.positioners = {
+ /**
+ * Average mode places the tooltip at the average position of the elements shown
+ * @function Chart.Tooltip.positioners.average
+ * @param elements {ChartElement[]} the elements being displayed in the tooltip
+ * @returns {Point} tooltip position
+ */
+ average: function(elements) {
+ if (!elements.length) {
+ return false;
+ }
+
+ var i, len;
+ var x = 0;
+ var y = 0;
+ var count = 0;
+
+ for (i = 0, len = elements.length; i < len; ++i) {
+ var el = elements[i];
+ if (el && el.hasValue()) {
+ var pos = el.tooltipPosition();
+ x += pos.x;
+ y += pos.y;
+ ++count;
+ }
+ }
+
+ return {
+ x: Math.round(x / count),
+ y: Math.round(y / count)
+ };
+ },
+
+ /**
+ * Gets the tooltip position nearest of the item nearest to the event position
+ * @function Chart.Tooltip.positioners.nearest
+ * @param elements {Chart.Element[]} the tooltip elements
+ * @param eventPosition {Point} the position of the event in canvas coordinates
+ * @returns {Point} the tooltip position
+ */
+ nearest: function(elements, eventPosition) {
+ var x = eventPosition.x;
+ var y = eventPosition.y;
+
+ var nearestElement;
+ var minDistance = Number.POSITIVE_INFINITY;
+ var i, len;
+ for (i = 0, len = elements.length; i < len; ++i) {
+ var el = elements[i];
+ if (el && el.hasValue()) {
+ var center = el.getCenterPoint();
+ var d = helpers.distanceBetweenPoints(eventPosition, center);
+
+ if (d < minDistance) {
+ minDistance = d;
+ nearestElement = el;
+ }
+ }
+ }
+
+ if (nearestElement) {
+ var tp = nearestElement.tooltipPosition();
+ x = tp.x;
+ y = tp.y;
+ }
+
+ return {
+ x: x,
+ y: y
+ };
+ }
+ };
+};
+
+},{}],35:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers,
+ globalOpts = Chart.defaults.global;
+
+ globalOpts.elements.arc = {
+ backgroundColor: globalOpts.defaultColor,
+ borderColor: '#fff',
+ borderWidth: 2
+ };
+
+ Chart.elements.Arc = Chart.Element.extend({
+ inLabelRange: function(mouseX) {
+ var vm = this._view;
+
+ if (vm) {
+ return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
+ }
+ return false;
+ },
+ inRange: function(chartX, chartY) {
+ var vm = this._view;
+
+ if (vm) {
+ var pointRelativePosition = helpers.getAngleFromPoint(vm, {
+ x: chartX,
+ y: chartY
+ }),
+ angle = pointRelativePosition.angle,
+ distance = pointRelativePosition.distance;
+
+ // Sanitise angle range
+ var startAngle = vm.startAngle;
+ var endAngle = vm.endAngle;
+ while (endAngle < startAngle) {
+ endAngle += 2.0 * Math.PI;
+ }
+ while (angle > endAngle) {
+ angle -= 2.0 * Math.PI;
+ }
+ while (angle < startAngle) {
+ angle += 2.0 * Math.PI;
+ }
+
+ // Check if within the range of the open/close angle
+ var betweenAngles = (angle >= startAngle && angle <= endAngle),
+ withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
+
+ return (betweenAngles && withinRadius);
+ }
+ return false;
+ },
+ getCenterPoint: function() {
+ var vm = this._view;
+ var halfAngle = (vm.startAngle + vm.endAngle) / 2;
+ var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
+ return {
+ x: vm.x + Math.cos(halfAngle) * halfRadius,
+ y: vm.y + Math.sin(halfAngle) * halfRadius
+ };
+ },
+ getArea: function() {
+ var vm = this._view;
+ return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+
+ var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
+ rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
+ return {
+ x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
+ y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
+ };
+ },
+ draw: function() {
+
+ var ctx = this._chart.ctx,
+ vm = this._view,
+ sA = vm.startAngle,
+ eA = vm.endAngle;
+
+ ctx.beginPath();
+
+ ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
+ ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
+
+ ctx.closePath();
+ ctx.strokeStyle = vm.borderColor;
+ ctx.lineWidth = vm.borderWidth;
+
+ ctx.fillStyle = vm.backgroundColor;
+
+ ctx.fill();
+ ctx.lineJoin = 'bevel';
+
+ if (vm.borderWidth) {
+ ctx.stroke();
+ }
+ }
+ });
+};
+
+},{}],36:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ var globalDefaults = Chart.defaults.global;
+
+ Chart.defaults.global.elements.line = {
+ tension: 0.4,
+ backgroundColor: globalDefaults.defaultColor,
+ borderWidth: 3,
+ borderColor: globalDefaults.defaultColor,
+ borderCapStyle: 'butt',
+ borderDash: [],
+ borderDashOffset: 0.0,
+ borderJoinStyle: 'miter',
+ capBezierPoints: true,
+ fill: true, // do we fill in the area between the line and its base axis
+ };
+
+ Chart.elements.Line = Chart.Element.extend({
+ draw: function() {
+ var me = this;
+ var vm = me._view;
+ var ctx = me._chart.ctx;
+ var spanGaps = vm.spanGaps;
+ var points = me._children.slice(); // clone array
+ var globalOptionLineElements = globalDefaults.elements.line;
+ var lastDrawnIndex = -1;
+ var index, current, previous, currentVM;
+
+ // If we are looping, adding the first point again
+ if (me._loop && points.length) {
+ points.push(points[0]);
+ }
+
+ ctx.save();
+
+ // Stroke Line Options
+ ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
+
+ // IE 9 and 10 do not support line dash
+ if (ctx.setLineDash) {
+ ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
+ }
+
+ ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
+ ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
+ ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
+ ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
+
+ // Stroke Line
+ ctx.beginPath();
+ lastDrawnIndex = -1;
+
+ for (index = 0; index < points.length; ++index) {
+ current = points[index];
+ previous = helpers.previousItem(points, index);
+ currentVM = current._view;
+
+ // First point moves to it's starting position no matter what
+ if (index === 0) {
+ if (!currentVM.skip) {
+ ctx.moveTo(currentVM.x, currentVM.y);
+ lastDrawnIndex = index;
+ }
+ } else {
+ previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
+
+ if (!currentVM.skip) {
+ if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
+ // There was a gap and this is the first point after the gap
+ ctx.moveTo(currentVM.x, currentVM.y);
+ } else {
+ // Line to next point
+ helpers.canvas.lineTo(ctx, previous._view, current._view);
+ }
+ lastDrawnIndex = index;
+ }
+ }
+ }
+
+ ctx.stroke();
+ ctx.restore();
+ }
+ });
+};
+
+},{}],37:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers,
+ globalOpts = Chart.defaults.global,
+ defaultColor = globalOpts.defaultColor;
+
+ globalOpts.elements.point = {
+ radius: 3,
+ pointStyle: 'circle',
+ backgroundColor: defaultColor,
+ borderWidth: 1,
+ borderColor: defaultColor,
+ // Hover
+ hitRadius: 1,
+ hoverRadius: 4,
+ hoverBorderWidth: 1
+ };
+
+ function xRange(mouseX) {
+ var vm = this._view;
+ return vm ? (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
+ }
+
+ function yRange(mouseY) {
+ var vm = this._view;
+ return vm ? (Math.pow(mouseY - vm.y, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
+ }
+
+ Chart.elements.Point = Chart.Element.extend({
+ inRange: function(mouseX, mouseY) {
+ var vm = this._view;
+ return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
+ },
+
+ inLabelRange: xRange,
+ inXRange: xRange,
+ inYRange: yRange,
+
+ getCenterPoint: function() {
+ var vm = this._view;
+ return {
+ x: vm.x,
+ y: vm.y
+ };
+ },
+ getArea: function() {
+ return Math.PI * Math.pow(this._view.radius, 2);
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+ return {
+ x: vm.x,
+ y: vm.y,
+ padding: vm.radius + vm.borderWidth
+ };
+ },
+ draw: function(chartArea) {
+ var vm = this._view;
+ var model = this._model;
+ var ctx = this._chart.ctx;
+ var pointStyle = vm.pointStyle;
+ var radius = vm.radius;
+ var x = vm.x;
+ var y = vm.y;
+ var color = Chart.helpers.color;
+ var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
+ var ratio = 0;
+
+ if (vm.skip) {
+ return;
+ }
+
+ ctx.strokeStyle = vm.borderColor || defaultColor;
+ ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth);
+ ctx.fillStyle = vm.backgroundColor || defaultColor;
+
+ // Cliping for Points.
+ // going out from inner charArea?
+ if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right*errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom*errMargin < model.y))) {
+ // Point fade out
+ if (model.x < chartArea.left) {
+ ratio = (x - model.x) / (chartArea.left - model.x);
+ } else if (chartArea.right*errMargin < model.x) {
+ ratio = (model.x - x) / (model.x - chartArea.right);
+ } else if (model.y < chartArea.top) {
+ ratio = (y - model.y) / (chartArea.top - model.y);
+ } else if (chartArea.bottom*errMargin < model.y) {
+ ratio = (model.y - y) / (model.y - chartArea.bottom);
+ }
+ ratio = Math.round(ratio*100) / 100;
+ ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
+ ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
+ }
+
+ Chart.canvasHelpers.drawPoint(ctx, pointStyle, radius, x, y);
+ }
+ });
+};
+
+},{}],38:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var globalOpts = Chart.defaults.global;
+
+ globalOpts.elements.rectangle = {
+ backgroundColor: globalOpts.defaultColor,
+ borderWidth: 0,
+ borderColor: globalOpts.defaultColor,
+ borderSkipped: 'bottom'
+ };
+
+ function isVertical(bar) {
+ return bar._view.width !== undefined;
+ }
+
+ /**
+ * Helper function to get the bounds of the bar regardless of the orientation
+ * @private
+ * @param bar {Chart.Element.Rectangle} the bar
+ * @return {Bounds} bounds of the bar
+ */
+ function getBarBounds(bar) {
+ var vm = bar._view;
+ var x1, x2, y1, y2;
+
+ if (isVertical(bar)) {
+ // vertical
+ var halfWidth = vm.width / 2;
+ x1 = vm.x - halfWidth;
+ x2 = vm.x + halfWidth;
+ y1 = Math.min(vm.y, vm.base);
+ y2 = Math.max(vm.y, vm.base);
+ } else {
+ // horizontal bar
+ var halfHeight = vm.height / 2;
+ x1 = Math.min(vm.x, vm.base);
+ x2 = Math.max(vm.x, vm.base);
+ y1 = vm.y - halfHeight;
+ y2 = vm.y + halfHeight;
+ }
+
+ return {
+ left: x1,
+ top: y1,
+ right: x2,
+ bottom: y2
+ };
+ }
+
+ Chart.elements.Rectangle = Chart.Element.extend({
+ draw: function() {
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+ var left, right, top, bottom, signX, signY, borderSkipped;
+ var borderWidth = vm.borderWidth;
+
+ if (!vm.horizontal) {
+ // bar
+ left = vm.x - vm.width / 2;
+ right = vm.x + vm.width / 2;
+ top = vm.y;
+ bottom = vm.base;
+ signX = 1;
+ signY = bottom > top? 1: -1;
+ borderSkipped = vm.borderSkipped || 'bottom';
+ } else {
+ // horizontal bar
+ left = vm.base;
+ right = vm.x;
+ top = vm.y - vm.height / 2;
+ bottom = vm.y + vm.height / 2;
+ signX = right > left? 1: -1;
+ signY = 1;
+ borderSkipped = vm.borderSkipped || 'left';
+ }
+
+ // Canvas doesn't allow us to stroke inside the width so we can
+ // adjust the sizes to fit if we're setting a stroke on the line
+ if (borderWidth) {
+ // borderWidth shold be less than bar width and bar height.
+ var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
+ borderWidth = borderWidth > barSize? barSize: borderWidth;
+ var halfStroke = borderWidth / 2;
+ // Adjust borderWidth when bar top position is near vm.base(zero).
+ var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
+ var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
+ var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
+ var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
+ // not become a vertical line?
+ if (borderLeft !== borderRight) {
+ top = borderTop;
+ bottom = borderBottom;
+ }
+ // not become a horizontal line?
+ if (borderTop !== borderBottom) {
+ left = borderLeft;
+ right = borderRight;
+ }
+ }
+
+ ctx.beginPath();
+ ctx.fillStyle = vm.backgroundColor;
+ ctx.strokeStyle = vm.borderColor;
+ ctx.lineWidth = borderWidth;
+
+ // Corner points, from bottom-left to bottom-right clockwise
+ // | 1 2 |
+ // | 0 3 |
+ var corners = [
+ [left, bottom],
+ [left, top],
+ [right, top],
+ [right, bottom]
+ ];
+
+ // Find first (starting) corner with fallback to 'bottom'
+ var borders = ['bottom', 'left', 'top', 'right'];
+ var startCorner = borders.indexOf(borderSkipped, 0);
+ if (startCorner === -1) {
+ startCorner = 0;
+ }
+
+ function cornerAt(index) {
+ return corners[(startCorner + index) % 4];
+ }
+
+ // Draw rectangle from 'startCorner'
+ var corner = cornerAt(0);
+ ctx.moveTo(corner[0], corner[1]);
+
+ for (var i = 1; i < 4; i++) {
+ corner = cornerAt(i);
+ ctx.lineTo(corner[0], corner[1]);
+ }
+
+ ctx.fill();
+ if (borderWidth) {
+ ctx.stroke();
+ }
+ },
+ height: function() {
+ var vm = this._view;
+ return vm.base - vm.y;
+ },
+ inRange: function(mouseX, mouseY) {
+ var inRange = false;
+
+ if (this._view) {
+ var bounds = getBarBounds(this);
+ inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
+ }
+
+ return inRange;
+ },
+ inLabelRange: function(mouseX, mouseY) {
+ var me = this;
+ if (!me._view) {
+ return false;
+ }
+
+ var inRange = false;
+ var bounds = getBarBounds(me);
+
+ if (isVertical(me)) {
+ inRange = mouseX >= bounds.left && mouseX <= bounds.right;
+ } else {
+ inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
+ }
+
+ return inRange;
+ },
+ inXRange: function(mouseX) {
+ var bounds = getBarBounds(this);
+ return mouseX >= bounds.left && mouseX <= bounds.right;
+ },
+ inYRange: function(mouseY) {
+ var bounds = getBarBounds(this);
+ return mouseY >= bounds.top && mouseY <= bounds.bottom;
+ },
+ getCenterPoint: function() {
+ var vm = this._view;
+ var x, y;
+ if (isVertical(this)) {
+ x = vm.x;
+ y = (vm.y + vm.base) / 2;
+ } else {
+ x = (vm.x + vm.base) / 2;
+ y = vm.y;
+ }
+
+ return {x: x, y: y};
+ },
+ getArea: function() {
+ var vm = this._view;
+ return vm.width * Math.abs(vm.y - vm.base);
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+ return {
+ x: vm.x,
+ y: vm.y
+ };
+ }
+ });
+
+};
+
+},{}],39:[function(require,module,exports){
+'use strict';
+
+// Chart.Platform implementation for targeting a web browser
+module.exports = function(Chart) {
+ var helpers = Chart.helpers;
+
+ // DOM event types -> Chart.js event types.
+ // Note: only events with different types are mapped.
+ // https://developer.mozilla.org/en-US/docs/Web/Events
+ var eventTypeMap = {
+ // Touch events
+ touchstart: 'mousedown',
+ touchmove: 'mousemove',
+ touchend: 'mouseup',
+
+ // Pointer events
+ pointerenter: 'mouseenter',
+ pointerdown: 'mousedown',
+ pointermove: 'mousemove',
+ pointerup: 'mouseup',
+ pointerleave: 'mouseout',
+ pointerout: 'mouseout'
+ };
+
+ /**
+ * The "used" size is the final value of a dimension property after all calculations have
+ * been performed. This method uses the computed style of `element` but returns undefined
+ * if the computed style is not expressed in pixels. That can happen in some cases where
+ * `element` has a size relative to its parent and this last one is not yet displayed,
+ * for example because of `display: none` on a parent node.
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
+ * @returns {Number} Size in pixels or undefined if unknown.
+ */
+ function readUsedSize(element, property) {
+ var value = helpers.getStyle(element, property);
+ var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
+ return matches? Number(matches[1]) : undefined;
+ }
+
+ /**
+ * Initializes the canvas style and render size without modifying the canvas display size,
+ * since responsiveness is handled by the controller.resize() method. The config is used
+ * to determine the aspect ratio to apply in case no explicit height has been specified.
+ */
+ function initCanvas(canvas, config) {
+ var style = canvas.style;
+
+ // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
+ // returns null or '' if no explicit value has been set to the canvas attribute.
+ var renderHeight = canvas.getAttribute('height');
+ var renderWidth = canvas.getAttribute('width');
+
+ // Chart.js modifies some canvas values that we want to restore on destroy
+ canvas._chartjs = {
+ initial: {
+ height: renderHeight,
+ width: renderWidth,
+ style: {
+ display: style.display,
+ height: style.height,
+ width: style.width
+ }
+ }
+ };
+
+ // Force canvas to display as block to avoid extra space caused by inline
+ // elements, which would interfere with the responsive resize process.
+ // https://github.com/chartjs/Chart.js/issues/2538
+ style.display = style.display || 'block';
+
+ if (renderWidth === null || renderWidth === '') {
+ var displayWidth = readUsedSize(canvas, 'width');
+ if (displayWidth !== undefined) {
+ canvas.width = displayWidth;
+ }
+ }
+
+ if (renderHeight === null || renderHeight === '') {
+ if (canvas.style.height === '') {
+ // If no explicit render height and style height, let's apply the aspect ratio,
+ // which one can be specified by the user but also by charts as default option
+ // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
+ canvas.height = canvas.width / (config.options.aspectRatio || 2);
+ } else {
+ var displayHeight = readUsedSize(canvas, 'height');
+ if (displayWidth !== undefined) {
+ canvas.height = displayHeight;
+ }
+ }
+ }
+
+ return canvas;
+ }
+
+ function createEvent(type, chart, x, y, nativeEvent) {
+ return {
+ type: type,
+ chart: chart,
+ native: nativeEvent || null,
+ x: x !== undefined? x : null,
+ y: y !== undefined? y : null,
+ };
+ }
+
+ function fromNativeEvent(event, chart) {
+ var type = eventTypeMap[event.type] || event.type;
+ var pos = helpers.getRelativePosition(event, chart);
+ return createEvent(type, chart, pos.x, pos.y, event);
+ }
+
+ function createResizer(handler) {
+ var iframe = document.createElement('iframe');
+ iframe.className = 'chartjs-hidden-iframe';
+ iframe.style.cssText =
+ 'display:block;'+
+ 'overflow:hidden;'+
+ 'border:0;'+
+ 'margin:0;'+
+ 'top:0;'+
+ 'left:0;'+
+ 'bottom:0;'+
+ 'right:0;'+
+ 'height:100%;'+
+ 'width:100%;'+
+ 'position:absolute;'+
+ 'pointer-events:none;'+
+ 'z-index:-1;';
+
+ // Prevent the iframe to gain focus on tab.
+ // https://github.com/chartjs/Chart.js/issues/3090
+ iframe.tabIndex = -1;
+
+ // If the iframe is re-attached to the DOM, the resize listener is removed because the
+ // content is reloaded, so make sure to install the handler after the iframe is loaded.
+ // https://github.com/chartjs/Chart.js/issues/3521
+ helpers.addEvent(iframe, 'load', function() {
+ helpers.addEvent(iframe.contentWindow || iframe, 'resize', handler);
+
+ // The iframe size might have changed while loading, which can also
+ // happen if the size has been changed while detached from the DOM.
+ handler();
+ });
+
+ return iframe;
+ }
+
+ function addResizeListener(node, listener, chart) {
+ var stub = node._chartjs = {
+ ticking: false
+ };
+
+ // Throttle the callback notification until the next animation frame.
+ var notify = function() {
+ if (!stub.ticking) {
+ stub.ticking = true;
+ helpers.requestAnimFrame.call(window, function() {
+ if (stub.resizer) {
+ stub.ticking = false;
+ return listener(createEvent('resize', chart));
+ }
+ });
+ }
+ };
+
+ // Let's keep track of this added iframe and thus avoid DOM query when removing it.
+ stub.resizer = createResizer(notify);
+
+ node.insertBefore(stub.resizer, node.firstChild);
+ }
+
+ function removeResizeListener(node) {
+ if (!node || !node._chartjs) {
+ return;
+ }
+
+ var resizer = node._chartjs.resizer;
+ if (resizer) {
+ resizer.parentNode.removeChild(resizer);
+ node._chartjs.resizer = null;
+ }
+
+ delete node._chartjs;
+ }
+
+ return {
+ acquireContext: function(item, config) {
+ if (typeof item === 'string') {
+ item = document.getElementById(item);
+ } else if (item.length) {
+ // Support for array based queries (such as jQuery)
+ item = item[0];
+ }
+
+ if (item && item.canvas) {
+ // Support for any object associated to a canvas (including a context2d)
+ item = item.canvas;
+ }
+
+ // To prevent canvas fingerprinting, some add-ons undefine the getContext
+ // method, for example: https://github.com/kkapsner/CanvasBlocker
+ // https://github.com/chartjs/Chart.js/issues/2807
+ var context = item && item.getContext && item.getContext('2d');
+
+ // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
+ // inside an iframe or when running in a protected environment. We could guess the
+ // types from their toString() value but let's keep things flexible and assume it's
+ // a sufficient condition if the item has a context2D which has item as `canvas`.
+ // https://github.com/chartjs/Chart.js/issues/3887
+ // https://github.com/chartjs/Chart.js/issues/4102
+ // https://github.com/chartjs/Chart.js/issues/4152
+ if (context && context.canvas === item) {
+ initCanvas(item, config);
+ return context;
+ }
+
+ return null;
+ },
+
+ releaseContext: function(context) {
+ var canvas = context.canvas;
+ if (!canvas._chartjs) {
+ return;
+ }
+
+ var initial = canvas._chartjs.initial;
+ ['height', 'width'].forEach(function(prop) {
+ var value = initial[prop];
+ if (value === undefined || value === null) {
+ canvas.removeAttribute(prop);
+ } else {
+ canvas.setAttribute(prop, value);
+ }
+ });
+
+ helpers.each(initial.style || {}, function(value, key) {
+ canvas.style[key] = value;
+ });
+
+ // The canvas render size might have been changed (and thus the state stack discarded),
+ // we can't use save() and restore() to restore the initial state. So make sure that at
+ // least the canvas context is reset to the default state by setting the canvas width.
+ // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
+ canvas.width = canvas.width;
+
+ delete canvas._chartjs;
+ },
+
+ addEventListener: function(chart, type, listener) {
+ var canvas = chart.canvas;
+ if (type === 'resize') {
+ // Note: the resize event is not supported on all browsers.
+ addResizeListener(canvas.parentNode, listener, chart);
+ return;
+ }
+
+ var stub = listener._chartjs || (listener._chartjs = {});
+ var proxies = stub.proxies || (stub.proxies = {});
+ var proxy = proxies[chart.id + '_' + type] = function(event) {
+ listener(fromNativeEvent(event, chart));
+ };
+
+ helpers.addEvent(canvas, type, proxy);
+ },
+
+ removeEventListener: function(chart, type, listener) {
+ var canvas = chart.canvas;
+ if (type === 'resize') {
+ // Note: the resize event is not supported on all browsers.
+ removeResizeListener(canvas.parentNode, listener);
+ return;
+ }
+
+ var stub = listener._chartjs || {};
+ var proxies = stub.proxies || {};
+ var proxy = proxies[chart.id + '_' + type];
+ if (!proxy) {
+ return;
+ }
+
+ helpers.removeEvent(canvas, type, proxy);
+ }
+ };
+};
+
+},{}],40:[function(require,module,exports){
+'use strict';
+
+// By default, select the browser (DOM) platform.
+// @TODO Make possible to select another platform at build time.
+var implementation = require(39);
+
+module.exports = function(Chart) {
+ /**
+ * @namespace Chart.platform
+ * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
+ * @since 2.4.0
+ */
+ Chart.platform = {
+ /**
+ * Called at chart construction time, returns a context2d instance implementing
+ * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
+ * @param {*} item - The native item from which to acquire context (platform specific)
+ * @param {Object} options - The chart options
+ * @returns {CanvasRenderingContext2D} context2d instance
+ */
+ acquireContext: function() {},
+
+ /**
+ * Called at chart destruction time, releases any resources associated to the context
+ * previously returned by the acquireContext() method.
+ * @param {CanvasRenderingContext2D} context - The context2d instance
+ * @returns {Boolean} true if the method succeeded, else false
+ */
+ releaseContext: function() {},
+
+ /**
+ * Registers the specified listener on the given chart.
+ * @param {Chart} chart - Chart from which to listen for event
+ * @param {String} type - The ({@link IEvent}) type to listen for
+ * @param {Function} listener - Receives a notification (an object that implements
+ * the {@link IEvent} interface) when an event of the specified type occurs.
+ */
+ addEventListener: function() {},
+
+ /**
+ * Removes the specified listener previously registered with addEventListener.
+ * @param {Chart} chart -Chart from which to remove the listener
+ * @param {String} type - The ({@link IEvent}) type to remove
+ * @param {Function} listener - The listener function to remove from the event target.
+ */
+ removeEventListener: function() {}
+ };
+
+ /**
+ * @interface IPlatform
+ * Allows abstracting platform dependencies away from the chart
+ * @borrows Chart.platform.acquireContext as acquireContext
+ * @borrows Chart.platform.releaseContext as releaseContext
+ * @borrows Chart.platform.addEventListener as addEventListener
+ * @borrows Chart.platform.removeEventListener as removeEventListener
+ */
+
+ /**
+ * @interface IEvent
+ * @prop {String} type - The event type name, possible values are:
+ * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
+ * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
+ * @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
+ * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
+ * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
+ */
+
+ Chart.helpers.extend(Chart.platform, implementation(Chart));
+};
+
+},{"39":39}],41:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+ /**
+ * Plugin based on discussion from the following Chart.js issues:
+ * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569
+ * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897
+ */
+ Chart.defaults.global.plugins.filler = {
+ propagate: true
+ };
+
+ var defaults = Chart.defaults;
+ var helpers = Chart.helpers;
+ var mappers = {
+ dataset: function(source) {
+ var index = source.fill;
+ var chart = source.chart;
+ var meta = chart.getDatasetMeta(index);
+ var visible = meta && chart.isDatasetVisible(index);
+ var points = (visible && meta.dataset._children) || [];
+
+ return !points.length? null : function(point, i) {
+ return points[i]._view || null;
+ };
+ },
+
+ boundary: function(source) {
+ var boundary = source.boundary;
+ var x = boundary? boundary.x : null;
+ var y = boundary? boundary.y : null;
+
+ return function(point) {
+ return {
+ x: x === null? point.x : x,
+ y: y === null? point.y : y,
+ };
+ };
+ }
+ };
+
+ // @todo if (fill[0] === '#')
+ function decodeFill(el, index, count) {
+ var model = el._model || {};
+ var fill = model.fill;
+ var target;
+
+ if (fill === undefined) {
+ fill = !!model.backgroundColor;
+ }
+
+ if (fill === false || fill === null) {
+ return false;
+ }
+
+ if (fill === true) {
+ return 'origin';
+ }
+
+ target = parseFloat(fill, 10);
+ if (isFinite(target) && Math.floor(target) === target) {
+ if (fill[0] === '-' || fill[0] === '+') {
+ target = index + target;
+ }
+
+ if (target === index || target < 0 || target >= count) {
+ return false;
+ }
+
+ return target;
+ }
+
+ switch (fill) {
+ // compatibility
+ case 'bottom':
+ return 'start';
+ case 'top':
+ return 'end';
+ case 'zero':
+ return 'origin';
+ // supported boundaries
+ case 'origin':
+ case 'start':
+ case 'end':
+ return fill;
+ // invalid fill values
+ default:
+ return false;
+ }
+ }
+
+ function computeBoundary(source) {
+ var model = source.el._model || {};
+ var scale = source.el._scale || {};
+ var fill = source.fill;
+ var target = null;
+ var horizontal;
+
+ if (isFinite(fill)) {
+ return null;
+ }
+
+ // Backward compatibility: until v3, we still need to support boundary values set on
+ // the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
+ // controllers might still use it (e.g. the Smith chart).
+
+ if (fill === 'start') {
+ target = model.scaleBottom === undefined? scale.bottom : model.scaleBottom;
+ } else if (fill === 'end') {
+ target = model.scaleTop === undefined? scale.top : model.scaleTop;
+ } else if (model.scaleZero !== undefined) {
+ target = model.scaleZero;
+ } else if (scale.getBasePosition) {
+ target = scale.getBasePosition();
+ } else if (scale.getBasePixel) {
+ target = scale.getBasePixel();
+ }
+
+ if (target !== undefined && target !== null) {
+ if (target.x !== undefined && target.y !== undefined) {
+ return target;
+ }
+
+ if (typeof target === 'number' && isFinite(target)) {
+ horizontal = scale.isHorizontal();
+ return {
+ x: horizontal? target : null,
+ y: horizontal? null : target
+ };
+ }
+ }
+
+ return null;
+ }
+
+ function resolveTarget(sources, index, propagate) {
+ var source = sources[index];
+ var fill = source.fill;
+ var visited = [index];
+ var target;
+
+ if (!propagate) {
+ return fill;
+ }
+
+ while (fill !== false && visited.indexOf(fill) === -1) {
+ if (!isFinite(fill)) {
+ return fill;
+ }
+
+ target = sources[fill];
+ if (!target) {
+ return false;
+ }
+
+ if (target.visible) {
+ return fill;
+ }
+
+ visited.push(fill);
+ fill = target.fill;
+ }
+
+ return false;
+ }
+
+ function createMapper(source) {
+ var fill = source.fill;
+ var type = 'dataset';
+
+ if (fill === false) {
+ return null;
+ }
+
+ if (!isFinite(fill)) {
+ type = 'boundary';
+ }
+
+ return mappers[type](source);
+ }
+
+ function isDrawable(point) {
+ return point && !point.skip;
+ }
+
+ function drawArea(ctx, curve0, curve1, len0, len1) {
+ var i;
+
+ if (!len0 || !len1) {
+ return;
+ }
+
+ // building first area curve (normal)
+ ctx.moveTo(curve0[0].x, curve0[0].y);
+ for (i=1; i0; --i) {
+ helpers.canvas.lineTo(ctx, curve1[i], curve1[i-1], true);
+ }
+ }
+
+ function doFill(ctx, points, mapper, view, color, loop) {
+ var count = points.length;
+ var span = view.spanGaps;
+ var curve0 = [];
+ var curve1 = [];
+ var len0 = 0;
+ var len1 = 0;
+ var i, ilen, index, p0, p1, d0, d1;
+
+ ctx.beginPath();
+
+ for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
+ index = i%count;
+ p0 = points[index]._view;
+ p1 = mapper(p0, index, view);
+ d0 = isDrawable(p0);
+ d1 = isDrawable(p1);
+
+ if (d0 && d1) {
+ len0 = curve0.push(p0);
+ len1 = curve1.push(p1);
+ } else if (len0 && len1) {
+ if (!span) {
+ drawArea(ctx, curve0, curve1, len0, len1);
+ len0 = len1 = 0;
+ curve0 = [];
+ curve1 = [];
+ } else {
+ if (d0) {
+ curve0.push(p0);
+ }
+ if (d1) {
+ curve1.push(p1);
+ }
+ }
+ }
+ }
+
+ drawArea(ctx, curve0, curve1, len0, len1);
+
+ ctx.closePath();
+ ctx.fillStyle = color;
+ ctx.fill();
+ }
+
+ return {
+ id: 'filler',
+
+ afterDatasetsUpdate: function(chart, options) {
+ var count = (chart.data.datasets || []).length;
+ var propagate = options.propagate;
+ var sources = [];
+ var meta, i, el, source;
+
+ for (i = 0; i < count; ++i) {
+ meta = chart.getDatasetMeta(i);
+ el = meta.dataset;
+ source = null;
+
+ if (el && el._model && el instanceof Chart.elements.Line) {
+ source = {
+ visible: chart.isDatasetVisible(i),
+ fill: decodeFill(el, i, count),
+ chart: chart,
+ el: el
+ };
+ }
+
+ meta.$filler = source;
+ sources.push(source);
+ }
+
+ for (i=0; i= me.width) {
+ totalHeight += fontSize + (labelOpts.padding);
+ lineWidths[lineWidths.length] = me.left;
+ }
+
+ // Store the hitbox width and height here. Final position will be updated in `draw`
+ hitboxes[i] = {
+ left: 0,
+ top: 0,
+ width: width,
+ height: fontSize
+ };
+
+ lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
+ });
+
+ minSize.height += totalHeight;
+
+ } else {
+ var vPadding = labelOpts.padding;
+ var columnWidths = me.columnWidths = [];
+ var totalWidth = labelOpts.padding;
+ var currentColWidth = 0;
+ var currentColHeight = 0;
+ var itemHeight = fontSize + vPadding;
+
+ helpers.each(me.legendItems, function(legendItem, i) {
+ var boxWidth = getBoxWidth(labelOpts, fontSize);
+ var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+
+ // If too tall, go to new column
+ if (currentColHeight + itemHeight > minSize.height) {
+ totalWidth += currentColWidth + labelOpts.padding;
+ columnWidths.push(currentColWidth); // previous column width
+
+ currentColWidth = 0;
+ currentColHeight = 0;
+ }
+
+ // Get max width
+ currentColWidth = Math.max(currentColWidth, itemWidth);
+ currentColHeight += itemHeight;
+
+ // Store the hitbox width and height here. Final position will be updated in `draw`
+ hitboxes[i] = {
+ left: 0,
+ top: 0,
+ width: itemWidth,
+ height: fontSize
+ };
+ });
+
+ totalWidth += currentColWidth;
+ columnWidths.push(currentColWidth);
+ minSize.width += totalWidth;
+ }
+ }
+
+ me.width = minSize.width;
+ me.height = minSize.height;
+ },
+ afterFit: noop,
+
+ // Shared Methods
+ isHorizontal: function() {
+ return this.options.position === 'top' || this.options.position === 'bottom';
+ },
+
+ // Actually draw the legend on the canvas
+ draw: function() {
+ var me = this;
+ var opts = me.options;
+ var labelOpts = opts.labels;
+ var globalDefault = Chart.defaults.global,
+ lineDefault = globalDefault.elements.line,
+ legendWidth = me.width,
+ lineWidths = me.lineWidths;
+
+ if (opts.display) {
+ var ctx = me.ctx,
+ cursor,
+ itemOrDefault = helpers.getValueOrDefault,
+ fontColor = itemOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor),
+ fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
+ fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
+ fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
+ labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
+
+ // Canvas setup
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ ctx.lineWidth = 0.5;
+ ctx.strokeStyle = fontColor; // for strikethrough effect
+ ctx.fillStyle = fontColor; // render in correct colour
+ ctx.font = labelFont;
+
+ var boxWidth = getBoxWidth(labelOpts, fontSize),
+ hitboxes = me.legendHitBoxes;
+
+ // current position
+ var drawLegendBox = function(x, y, legendItem) {
+ if (isNaN(boxWidth) || boxWidth <= 0) {
+ return;
+ }
+
+ // Set the ctx for the box
+ ctx.save();
+
+ ctx.fillStyle = itemOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
+ ctx.lineCap = itemOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
+ ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
+ ctx.lineJoin = itemOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
+ ctx.lineWidth = itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
+ ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
+ var isLineWidthZero = (itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);
+
+ if (ctx.setLineDash) {
+ // IE 9 and 10 do not support line dash
+ ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash));
+ }
+
+ if (opts.labels && opts.labels.usePointStyle) {
+ // Recalculate x and y for drawPoint() because its expecting
+ // x and y to be center of figure (instead of top left)
+ var radius = fontSize * Math.SQRT2 / 2;
+ var offSet = radius / Math.SQRT2;
+ var centerX = x + offSet;
+ var centerY = y + offSet;
+
+ // Draw pointStyle as legend symbol
+ Chart.canvasHelpers.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
+ } else {
+ // Draw box as legend symbol
+ if (!isLineWidthZero) {
+ ctx.strokeRect(x, y, boxWidth, fontSize);
+ }
+ ctx.fillRect(x, y, boxWidth, fontSize);
+ }
+
+ ctx.restore();
+ };
+ var fillText = function(x, y, legendItem, textWidth) {
+ ctx.fillText(legendItem.text, boxWidth + (fontSize / 2) + x, y);
+
+ if (legendItem.hidden) {
+ // Strikethrough the text if hidden
+ ctx.beginPath();
+ ctx.lineWidth = 2;
+ ctx.moveTo(boxWidth + (fontSize / 2) + x, y + (fontSize / 2));
+ ctx.lineTo(boxWidth + (fontSize / 2) + x + textWidth, y + (fontSize / 2));
+ ctx.stroke();
+ }
+ };
+
+ // Horizontal
+ var isHorizontal = me.isHorizontal();
+ if (isHorizontal) {
+ cursor = {
+ x: me.left + ((legendWidth - lineWidths[0]) / 2),
+ y: me.top + labelOpts.padding,
+ line: 0
+ };
+ } else {
+ cursor = {
+ x: me.left + labelOpts.padding,
+ y: me.top + labelOpts.padding,
+ line: 0
+ };
+ }
+
+ var itemHeight = fontSize + labelOpts.padding;
+ helpers.each(me.legendItems, function(legendItem, i) {
+ var textWidth = ctx.measureText(legendItem.text).width,
+ width = boxWidth + (fontSize / 2) + textWidth,
+ x = cursor.x,
+ y = cursor.y;
+
+ if (isHorizontal) {
+ if (x + width >= legendWidth) {
+ y = cursor.y += itemHeight;
+ cursor.line++;
+ x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
+ }
+ } else if (y + itemHeight > me.bottom) {
+ x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
+ y = cursor.y = me.top + labelOpts.padding;
+ cursor.line++;
+ }
+
+ drawLegendBox(x, y, legendItem);
+
+ hitboxes[i].left = x;
+ hitboxes[i].top = y;
+
+ // Fill the actual label
+ fillText(x, y, legendItem, textWidth);
+
+ if (isHorizontal) {
+ cursor.x += width + (labelOpts.padding);
+ } else {
+ cursor.y += itemHeight;
+ }
+
+ });
+ }
+ },
+
+ /**
+ * Handle an event
+ * @private
+ * @param {IEvent} event - The event to handle
+ * @return {Boolean} true if a change occured
+ */
+ handleEvent: function(e) {
+ var me = this;
+ var opts = me.options;
+ var type = e.type === 'mouseup' ? 'click' : e.type;
+ var changed = false;
+
+ if (type === 'mousemove') {
+ if (!opts.onHover) {
+ return;
+ }
+ } else if (type === 'click') {
+ if (!opts.onClick) {
+ return;
+ }
+ } else {
+ return;
+ }
+
+ // Chart event already has relative position in it
+ var x = e.x,
+ y = e.y;
+
+ if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
+ // See if we are touching one of the dataset boxes
+ var lh = me.legendHitBoxes;
+ for (var i = 0; i < lh.length; ++i) {
+ var hitBox = lh[i];
+
+ if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
+ // Touching an element
+ if (type === 'click') {
+ // use e.native for backwards compatibility
+ opts.onClick.call(me, e.native, me.legendItems[i]);
+ changed = true;
+ break;
+ } else if (type === 'mousemove') {
+ // use e.native for backwards compatibility
+ opts.onHover.call(me, e.native, me.legendItems[i]);
+ changed = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return changed;
+ }
+ });
+
+ function createNewLegendAndAttach(chart, legendOpts) {
+ var legend = new Chart.Legend({
+ ctx: chart.ctx,
+ options: legendOpts,
+ chart: chart
+ });
+
+ layout.configure(chart, legend, legendOpts);
+ layout.addBox(chart, legend);
+ chart.legend = legend;
+ }
+
+ return {
+ id: 'legend',
+
+ beforeInit: function(chart) {
+ var legendOpts = chart.options.legend;
+
+ if (legendOpts) {
+ createNewLegendAndAttach(chart, legendOpts);
+ }
+ },
+
+ beforeUpdate: function(chart) {
+ var legendOpts = chart.options.legend;
+ var legend = chart.legend;
+
+ if (legendOpts) {
+ legendOpts = helpers.configMerge(Chart.defaults.global.legend, legendOpts);
+
+ if (legend) {
+ layout.configure(chart, legend, legendOpts);
+ legend.options = legendOpts;
+ } else {
+ createNewLegendAndAttach(chart, legendOpts);
+ }
+ } else if (legend) {
+ layout.removeBox(chart, legend);
+ delete chart.legend;
+ }
+ },
+
+ afterEvent: function(chart, e) {
+ var legend = chart.legend;
+ if (legend) {
+ legend.handleEvent(e);
+ }
+ }
+ };
+};
+
+},{}],43:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ var layout = Chart.layoutService;
+ var noop = helpers.noop;
+
+ Chart.defaults.global.title = {
+ display: false,
+ position: 'top',
+ fullWidth: true,
+ weight: 2000, // by default greater than legend (1000) to be above
+ fontStyle: 'bold',
+ padding: 10,
+
+ // actual title
+ text: ''
+ };
+
+ Chart.Title = Chart.Element.extend({
+ initialize: function(config) {
+ var me = this;
+ helpers.extend(me, config);
+
+ // Contains hit boxes for each dataset (in dataset order)
+ me.legendHitBoxes = [];
+ },
+
+ // These methods are ordered by lifecycle. Utilities then follow.
+
+ beforeUpdate: noop,
+ update: function(maxWidth, maxHeight, margins) {
+ var me = this;
+
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+ me.beforeUpdate();
+
+ // Absorb the master measurements
+ me.maxWidth = maxWidth;
+ me.maxHeight = maxHeight;
+ me.margins = margins;
+
+ // Dimensions
+ me.beforeSetDimensions();
+ me.setDimensions();
+ me.afterSetDimensions();
+ // Labels
+ me.beforeBuildLabels();
+ me.buildLabels();
+ me.afterBuildLabels();
+
+ // Fit
+ me.beforeFit();
+ me.fit();
+ me.afterFit();
+ //
+ me.afterUpdate();
+
+ return me.minSize;
+
+ },
+ afterUpdate: noop,
+
+ //
+
+ beforeSetDimensions: noop,
+ setDimensions: function() {
+ var me = this;
+ // Set the unconstrained dimension before label rotation
+ if (me.isHorizontal()) {
+ // Reset position before calculating rotation
+ me.width = me.maxWidth;
+ me.left = 0;
+ me.right = me.width;
+ } else {
+ me.height = me.maxHeight;
+
+ // Reset position before calculating rotation
+ me.top = 0;
+ me.bottom = me.height;
+ }
+
+ // Reset padding
+ me.paddingLeft = 0;
+ me.paddingTop = 0;
+ me.paddingRight = 0;
+ me.paddingBottom = 0;
+
+ // Reset minSize
+ me.minSize = {
+ width: 0,
+ height: 0
+ };
+ },
+ afterSetDimensions: noop,
+
+ //
+
+ beforeBuildLabels: noop,
+ buildLabels: noop,
+ afterBuildLabels: noop,
+
+ //
+
+ beforeFit: noop,
+ fit: function() {
+ var me = this,
+ valueOrDefault = helpers.getValueOrDefault,
+ opts = me.options,
+ globalDefaults = Chart.defaults.global,
+ display = opts.display,
+ fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
+ minSize = me.minSize;
+
+ if (me.isHorizontal()) {
+ minSize.width = me.maxWidth; // fill all the width
+ minSize.height = display ? fontSize + (opts.padding * 2) : 0;
+ } else {
+ minSize.width = display ? fontSize + (opts.padding * 2) : 0;
+ minSize.height = me.maxHeight; // fill all the height
+ }
+
+ me.width = minSize.width;
+ me.height = minSize.height;
+
+ },
+ afterFit: noop,
+
+ // Shared Methods
+ isHorizontal: function() {
+ var pos = this.options.position;
+ return pos === 'top' || pos === 'bottom';
+ },
+
+ // Actually draw the title block on the canvas
+ draw: function() {
+ var me = this,
+ ctx = me.ctx,
+ valueOrDefault = helpers.getValueOrDefault,
+ opts = me.options,
+ globalDefaults = Chart.defaults.global;
+
+ if (opts.display) {
+ var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
+ fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle),
+ fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily),
+ titleFont = helpers.fontString(fontSize, fontStyle, fontFamily),
+ rotation = 0,
+ titleX,
+ titleY,
+ top = me.top,
+ left = me.left,
+ bottom = me.bottom,
+ right = me.right,
+ maxWidth;
+
+ ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
+ ctx.font = titleFont;
+
+ // Horizontal
+ if (me.isHorizontal()) {
+ titleX = left + ((right - left) / 2); // midpoint of the width
+ titleY = top + ((bottom - top) / 2); // midpoint of the height
+ maxWidth = right - left;
+ } else {
+ titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2);
+ titleY = top + ((bottom - top) / 2);
+ maxWidth = bottom - top;
+ rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
+ }
+
+ ctx.save();
+ ctx.translate(titleX, titleY);
+ ctx.rotate(rotation);
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillText(opts.text, 0, 0, maxWidth);
+ ctx.restore();
+ }
+ }
+ });
+
+ function createNewTitleBlockAndAttach(chart, titleOpts) {
+ var title = new Chart.Title({
+ ctx: chart.ctx,
+ options: titleOpts,
+ chart: chart
+ });
+
+ layout.configure(chart, title, titleOpts);
+ layout.addBox(chart, title);
+ chart.titleBlock = title;
+ }
+
+ return {
+ id: 'title',
+
+ beforeInit: function(chart) {
+ var titleOpts = chart.options.title;
+
+ if (titleOpts) {
+ createNewTitleBlockAndAttach(chart, titleOpts);
+ }
+ },
+
+ beforeUpdate: function(chart) {
+ var titleOpts = chart.options.title;
+ var titleBlock = chart.titleBlock;
+
+ if (titleOpts) {
+ titleOpts = helpers.configMerge(Chart.defaults.global.title, titleOpts);
+
+ if (titleBlock) {
+ layout.configure(chart, titleBlock, titleOpts);
+ titleBlock.options = titleOpts;
+ } else {
+ createNewTitleBlockAndAttach(chart, titleOpts);
+ }
+ } else if (titleBlock) {
+ Chart.layoutService.removeBox(chart, titleBlock);
+ delete chart.titleBlock;
+ }
+ }
+ };
+};
+
+},{}],44:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ // Default config for a category scale
+ var defaultConfig = {
+ position: 'bottom'
+ };
+
+ var DatasetScale = Chart.Scale.extend({
+ /**
+ * Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
+ * else fall back to data.labels
+ * @private
+ */
+ getLabels: function() {
+ var data = this.chart.data;
+ return (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
+ },
+
+ determineDataLimits: function() {
+ var me = this;
+ var labels = me.getLabels();
+ me.minIndex = 0;
+ me.maxIndex = labels.length - 1;
+ var findIndex;
+
+ if (me.options.ticks.min !== undefined) {
+ // user specified min value
+ findIndex = helpers.indexOf(labels, me.options.ticks.min);
+ me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
+ }
+
+ if (me.options.ticks.max !== undefined) {
+ // user specified max value
+ findIndex = helpers.indexOf(labels, me.options.ticks.max);
+ me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
+ }
+
+ me.min = labels[me.minIndex];
+ me.max = labels[me.maxIndex];
+ },
+
+ buildTicks: function() {
+ var me = this;
+ var labels = me.getLabels();
+ // If we are viewing some subset of labels, slice the original array
+ me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
+ },
+
+ getLabelForIndex: function(index, datasetIndex) {
+ var me = this;
+ var data = me.chart.data;
+ var isHorizontal = me.isHorizontal();
+
+ if (data.yLabels && !isHorizontal) {
+ return me.getRightValue(data.datasets[datasetIndex].data[index]);
+ }
+ return me.ticks[index - me.minIndex];
+ },
+
+ // Used to get data value locations. Value can either be an index or a numerical value
+ getPixelForValue: function(value, index, datasetIndex, includeOffset) {
+ var me = this;
+ // 1 is added because we need the length but we have the indexes
+ var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+
+ // If value is a data object, then index is the index in the data array,
+ // not the index of the scale. We need to change that.
+ var valueCategory;
+ if (value !== undefined && value !== null) {
+ valueCategory = me.isHorizontal() ? value.x : value.y;
+ }
+ if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
+ var labels = me.getLabels();
+ value = valueCategory || value;
+ var idx = labels.indexOf(value);
+ index = idx !== -1 ? idx : index;
+ }
+
+ if (me.isHorizontal()) {
+ var valueWidth = me.width / offsetAmt;
+ var widthOffset = (valueWidth * (index - me.minIndex));
+
+ if (me.options.gridLines.offsetGridLines && includeOffset || me.maxIndex === me.minIndex && includeOffset) {
+ widthOffset += (valueWidth / 2);
+ }
+
+ return me.left + Math.round(widthOffset);
+ }
+ var valueHeight = me.height / offsetAmt;
+ var heightOffset = (valueHeight * (index - me.minIndex));
+
+ if (me.options.gridLines.offsetGridLines && includeOffset) {
+ heightOffset += (valueHeight / 2);
+ }
+
+ return me.top + Math.round(heightOffset);
+ },
+ getPixelForTick: function(index, includeOffset) {
+ return this.getPixelForValue(this.ticks[index], index + this.minIndex, null, includeOffset);
+ },
+ getValueForPixel: function(pixel) {
+ var me = this;
+ var value;
+ var offsetAmt = Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+ var horz = me.isHorizontal();
+ var valueDimension = (horz ? me.width : me.height) / offsetAmt;
+
+ pixel -= horz ? me.left : me.top;
+
+ if (me.options.gridLines.offsetGridLines) {
+ pixel -= (valueDimension / 2);
+ }
+
+ if (pixel <= 0) {
+ value = 0;
+ } else {
+ value = Math.round(pixel / valueDimension);
+ }
+
+ return value;
+ },
+ getBasePixel: function() {
+ return this.bottom;
+ }
+ });
+
+ Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig);
+
+};
+
+},{}],45:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ var defaultConfig = {
+ position: 'left',
+ ticks: {
+ callback: Chart.Ticks.formatters.linear
+ }
+ };
+
+ var LinearScale = Chart.LinearScaleBase.extend({
+
+ determineDataLimits: function() {
+ var me = this;
+ var opts = me.options;
+ var chart = me.chart;
+ var data = chart.data;
+ var datasets = data.datasets;
+ var isHorizontal = me.isHorizontal();
+ var DEFAULT_MIN = 0;
+ var DEFAULT_MAX = 1;
+
+ function IDMatches(meta) {
+ return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+ }
+
+ // First Calculate the range
+ me.min = null;
+ me.max = null;
+
+ var hasStacks = opts.stacked;
+ if (hasStacks === undefined) {
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ if (hasStacks) {
+ return;
+ }
+
+ var meta = chart.getDatasetMeta(datasetIndex);
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+ meta.stack !== undefined) {
+ hasStacks = true;
+ }
+ });
+ }
+
+ if (opts.stacked || hasStacks) {
+ var valuesPerStack = {};
+
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+ var key = [
+ meta.type,
+ // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+ ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+ meta.stack
+ ].join('.');
+
+ if (valuesPerStack[key] === undefined) {
+ valuesPerStack[key] = {
+ positiveValues: [],
+ negativeValues: []
+ };
+ }
+
+ // Store these per type
+ var positiveValues = valuesPerStack[key].positiveValues;
+ var negativeValues = valuesPerStack[key].negativeValues;
+
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ positiveValues[index] = positiveValues[index] || 0;
+ negativeValues[index] = negativeValues[index] || 0;
+
+ if (opts.relativePoints) {
+ positiveValues[index] = 100;
+ } else if (value < 0) {
+ negativeValues[index] += value;
+ } else {
+ positiveValues[index] += value;
+ }
+ });
+ }
+ });
+
+ helpers.each(valuesPerStack, function(valuesForType) {
+ var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
+ var minVal = helpers.min(values);
+ var maxVal = helpers.max(values);
+ me.min = me.min === null ? minVal : Math.min(me.min, minVal);
+ me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
+ });
+
+ } else {
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ if (me.min === null) {
+ me.min = value;
+ } else if (value < me.min) {
+ me.min = value;
+ }
+
+ if (me.max === null) {
+ me.max = value;
+ } else if (value > me.max) {
+ me.max = value;
+ }
+ });
+ }
+ });
+ }
+
+ me.min = isFinite(me.min) ? me.min : DEFAULT_MIN;
+ me.max = isFinite(me.max) ? me.max : DEFAULT_MAX;
+
+ // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
+ this.handleTickRangeOptions();
+ },
+ getTickLimit: function() {
+ var maxTicks;
+ var me = this;
+ var tickOpts = me.options.ticks;
+
+ if (me.isHorizontal()) {
+ maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
+ } else {
+ // The factor of 2 used to scale the font size has been experimentally determined.
+ var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize);
+ maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
+ }
+
+ return maxTicks;
+ },
+ // Called after the ticks are built. We need
+ handleDirectionalChanges: function() {
+ if (!this.isHorizontal()) {
+ // We are in a vertical orientation. The top value is the highest. So reverse the array
+ this.ticks.reverse();
+ }
+ },
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+ // Utils
+ getPixelForValue: function(value) {
+ // This must be called after fit has been run so that
+ // this.left, this.top, this.right, and this.bottom have been defined
+ var me = this;
+ var start = me.start;
+
+ var rightValue = +me.getRightValue(value);
+ var pixel;
+ var range = me.end - start;
+
+ if (me.isHorizontal()) {
+ pixel = me.left + (me.width / range * (rightValue - start));
+ return Math.round(pixel);
+ }
+
+ pixel = me.bottom - (me.height / range * (rightValue - start));
+ return Math.round(pixel);
+ },
+ getValueForPixel: function(pixel) {
+ var me = this;
+ var isHorizontal = me.isHorizontal();
+ var innerDimension = isHorizontal ? me.width : me.height;
+ var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
+ return me.start + ((me.end - me.start) * offset);
+ },
+ getPixelForTick: function(index) {
+ return this.getPixelForValue(this.ticksAsNumbers[index]);
+ }
+ });
+ Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig);
+
+};
+
+},{}],46:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers,
+ noop = helpers.noop;
+
+ Chart.LinearScaleBase = Chart.Scale.extend({
+ handleTickRangeOptions: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+
+ // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
+ // do nothing since that would make the chart weird. If the user really wants a weird chart
+ // axis, they can manually override it
+ if (tickOpts.beginAtZero) {
+ var minSign = helpers.sign(me.min);
+ var maxSign = helpers.sign(me.max);
+
+ if (minSign < 0 && maxSign < 0) {
+ // move the top up to 0
+ me.max = 0;
+ } else if (minSign > 0 && maxSign > 0) {
+ // move the bottom down to 0
+ me.min = 0;
+ }
+ }
+
+ if (tickOpts.min !== undefined) {
+ me.min = tickOpts.min;
+ } else if (tickOpts.suggestedMin !== undefined) {
+ if (me.min === null) {
+ me.min = tickOpts.suggestedMin;
+ } else {
+ me.min = Math.min(me.min, tickOpts.suggestedMin);
+ }
+ }
+
+ if (tickOpts.max !== undefined) {
+ me.max = tickOpts.max;
+ } else if (tickOpts.suggestedMax !== undefined) {
+ if (me.max === null) {
+ me.max = tickOpts.suggestedMax;
+ } else {
+ me.max = Math.max(me.max, tickOpts.suggestedMax);
+ }
+ }
+
+ if (me.min === me.max) {
+ me.max++;
+
+ if (!tickOpts.beginAtZero) {
+ me.min--;
+ }
+ }
+ },
+ getTickLimit: noop,
+ handleDirectionalChanges: noop,
+
+ buildTicks: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+
+ // Figure out what the max number of ticks we can support it is based on the size of
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+ // the graph. Make sure we always have at least 2 ticks
+ var maxTicks = me.getTickLimit();
+ maxTicks = Math.max(2, maxTicks);
+
+ var numericGeneratorOptions = {
+ maxTicks: maxTicks,
+ min: tickOpts.min,
+ max: tickOpts.max,
+ stepSize: helpers.getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
+ };
+ var ticks = me.ticks = Chart.Ticks.generators.linear(numericGeneratorOptions, me);
+
+ me.handleDirectionalChanges();
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ me.max = helpers.max(ticks);
+ me.min = helpers.min(ticks);
+
+ if (tickOpts.reverse) {
+ ticks.reverse();
+
+ me.start = me.max;
+ me.end = me.min;
+ } else {
+ me.start = me.min;
+ me.end = me.max;
+ }
+ },
+ convertTicksToLabels: function() {
+ var me = this;
+ me.ticksAsNumbers = me.ticks.slice();
+ me.zeroLineIndex = me.ticks.indexOf(0);
+
+ Chart.Scale.prototype.convertTicksToLabels.call(me);
+ }
+ });
+};
+
+},{}],47:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ var defaultConfig = {
+ position: 'left',
+
+ // label settings
+ ticks: {
+ callback: Chart.Ticks.formatters.logarithmic
+ }
+ };
+
+ var LogarithmicScale = Chart.Scale.extend({
+ determineDataLimits: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+ var chart = me.chart;
+ var data = chart.data;
+ var datasets = data.datasets;
+ var getValueOrDefault = helpers.getValueOrDefault;
+ var isHorizontal = me.isHorizontal();
+ function IDMatches(meta) {
+ return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+ }
+
+ // Calculate Range
+ me.min = null;
+ me.max = null;
+ me.minNotZero = null;
+
+ var hasStacks = opts.stacked;
+ if (hasStacks === undefined) {
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ if (hasStacks) {
+ return;
+ }
+
+ var meta = chart.getDatasetMeta(datasetIndex);
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+ meta.stack !== undefined) {
+ hasStacks = true;
+ }
+ });
+ }
+
+ if (opts.stacked || hasStacks) {
+ var valuesPerStack = {};
+
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+ var key = [
+ meta.type,
+ // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+ ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+ meta.stack
+ ].join('.');
+
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+ if (valuesPerStack[key] === undefined) {
+ valuesPerStack[key] = [];
+ }
+
+ helpers.each(dataset.data, function(rawValue, index) {
+ var values = valuesPerStack[key];
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ values[index] = values[index] || 0;
+
+ if (opts.relativePoints) {
+ values[index] = 100;
+ } else {
+ // Don't need to split positive and negative since the log scale can't handle a 0 crossing
+ values[index] += value;
+ }
+ });
+ }
+ });
+
+ helpers.each(valuesPerStack, function(valuesForType) {
+ var minVal = helpers.min(valuesForType);
+ var maxVal = helpers.max(valuesForType);
+ me.min = me.min === null ? minVal : Math.min(me.min, minVal);
+ me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
+ });
+
+ } else {
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ if (me.min === null) {
+ me.min = value;
+ } else if (value < me.min) {
+ me.min = value;
+ }
+
+ if (me.max === null) {
+ me.max = value;
+ } else if (value > me.max) {
+ me.max = value;
+ }
+
+ if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
+ me.minNotZero = value;
+ }
+ });
+ }
+ });
+ }
+
+ me.min = getValueOrDefault(tickOpts.min, me.min);
+ me.max = getValueOrDefault(tickOpts.max, me.max);
+
+ if (me.min === me.max) {
+ if (me.min !== 0 && me.min !== null) {
+ me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
+ me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
+ } else {
+ me.min = 1;
+ me.max = 10;
+ }
+ }
+ },
+ buildTicks: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+
+ var generationOptions = {
+ min: tickOpts.min,
+ max: tickOpts.max
+ };
+ var ticks = me.ticks = Chart.Ticks.generators.logarithmic(generationOptions, me);
+
+ if (!me.isHorizontal()) {
+ // We are in a vertical orientation. The top value is the highest. So reverse the array
+ ticks.reverse();
+ }
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ me.max = helpers.max(ticks);
+ me.min = helpers.min(ticks);
+
+ if (tickOpts.reverse) {
+ ticks.reverse();
+
+ me.start = me.max;
+ me.end = me.min;
+ } else {
+ me.start = me.min;
+ me.end = me.max;
+ }
+ },
+ convertTicksToLabels: function() {
+ this.tickValues = this.ticks.slice();
+
+ Chart.Scale.prototype.convertTicksToLabels.call(this);
+ },
+ // Get the correct tooltip label
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+ getPixelForTick: function(index) {
+ return this.getPixelForValue(this.tickValues[index]);
+ },
+ getPixelForValue: function(value) {
+ var me = this;
+ var innerDimension;
+ var pixel;
+
+ var start = me.start;
+ var newVal = +me.getRightValue(value);
+ var range;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+
+ if (me.isHorizontal()) {
+ range = helpers.log10(me.end) - helpers.log10(start); // todo: if start === 0
+ if (newVal === 0) {
+ pixel = me.left;
+ } else {
+ innerDimension = me.width;
+ pixel = me.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
+ }
+ } else {
+ // Bottom - top since pixels increase downward on a screen
+ innerDimension = me.height;
+ if (start === 0 && !tickOpts.reverse) {
+ range = helpers.log10(me.end) - helpers.log10(me.minNotZero);
+ if (newVal === start) {
+ pixel = me.bottom;
+ } else if (newVal === me.minNotZero) {
+ pixel = me.bottom - innerDimension * 0.02;
+ } else {
+ pixel = me.bottom - innerDimension * 0.02 - (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
+ }
+ } else if (me.end === 0 && tickOpts.reverse) {
+ range = helpers.log10(me.start) - helpers.log10(me.minNotZero);
+ if (newVal === me.end) {
+ pixel = me.top;
+ } else if (newVal === me.minNotZero) {
+ pixel = me.top + innerDimension * 0.02;
+ } else {
+ pixel = me.top + innerDimension * 0.02 + (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
+ }
+ } else if (newVal === 0) {
+ pixel = tickOpts.reverse ? me.top : me.bottom;
+ } else {
+ range = helpers.log10(me.end) - helpers.log10(start);
+ innerDimension = me.height;
+ pixel = me.bottom - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
+ }
+ }
+ return pixel;
+ },
+ getValueForPixel: function(pixel) {
+ var me = this;
+ var range = helpers.log10(me.end) - helpers.log10(me.start);
+ var value, innerDimension;
+
+ if (me.isHorizontal()) {
+ innerDimension = me.width;
+ value = me.start * Math.pow(10, (pixel - me.left) * range / innerDimension);
+ } else { // todo: if start === 0
+ innerDimension = me.height;
+ value = Math.pow(10, (me.bottom - pixel) * range / innerDimension) / me.start;
+ }
+ return value;
+ }
+ });
+ Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);
+
+};
+
+},{}],48:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ var globalDefaults = Chart.defaults.global;
+
+ var defaultConfig = {
+ display: true,
+
+ // Boolean - Whether to animate scaling the chart from the centre
+ animate: true,
+ position: 'chartArea',
+
+ angleLines: {
+ display: true,
+ color: 'rgba(0, 0, 0, 0.1)',
+ lineWidth: 1
+ },
+
+ gridLines: {
+ circular: false
+ },
+
+ // label settings
+ ticks: {
+ // Boolean - Show a backdrop to the scale label
+ showLabelBackdrop: true,
+
+ // String - The colour of the label backdrop
+ backdropColor: 'rgba(255,255,255,0.75)',
+
+ // Number - The backdrop padding above & below the label in pixels
+ backdropPaddingY: 2,
+
+ // Number - The backdrop padding to the side of the label in pixels
+ backdropPaddingX: 2,
+
+ callback: Chart.Ticks.formatters.linear
+ },
+
+ pointLabels: {
+ // Boolean - if true, show point labels
+ display: true,
+
+ // Number - Point label font size in pixels
+ fontSize: 10,
+
+ // Function - Used to convert point labels
+ callback: function(label) {
+ return label;
+ }
+ }
+ };
+
+ function getValueCount(scale) {
+ var opts = scale.options;
+ return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
+ }
+
+ function getPointLabelFontOptions(scale) {
+ var pointLabelOptions = scale.options.pointLabels;
+ var fontSize = helpers.getValueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
+ var fontStyle = helpers.getValueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
+ var fontFamily = helpers.getValueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
+ var font = helpers.fontString(fontSize, fontStyle, fontFamily);
+
+ return {
+ size: fontSize,
+ style: fontStyle,
+ family: fontFamily,
+ font: font
+ };
+ }
+
+ function measureLabelSize(ctx, fontSize, label) {
+ if (helpers.isArray(label)) {
+ return {
+ w: helpers.longestText(ctx, ctx.font, label),
+ h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
+ };
+ }
+
+ return {
+ w: ctx.measureText(label).width,
+ h: fontSize
+ };
+ }
+
+ function determineLimits(angle, pos, size, min, max) {
+ if (angle === min || angle === max) {
+ return {
+ start: pos - (size / 2),
+ end: pos + (size / 2)
+ };
+ } else if (angle < min || angle > max) {
+ return {
+ start: pos - size - 5,
+ end: pos
+ };
+ }
+
+ return {
+ start: pos,
+ end: pos + size + 5
+ };
+ }
+
+ /**
+ * Helper function to fit a radial linear scale with point labels
+ */
+ function fitWithPointLabels(scale) {
+ /*
+ * Right, this is really confusing and there is a lot of maths going on here
+ * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
+ *
+ * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
+ *
+ * Solution:
+ *
+ * We assume the radius of the polygon is half the size of the canvas at first
+ * at each index we check if the text overlaps.
+ *
+ * Where it does, we store that angle and that index.
+ *
+ * After finding the largest index and angle we calculate how much we need to remove
+ * from the shape radius to move the point inwards by that x.
+ *
+ * We average the left and right distances to get the maximum shape radius that can fit in the box
+ * along with labels.
+ *
+ * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
+ * on each side, removing that from the size, halving it and adding the left x protrusion width.
+ *
+ * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
+ * and position it in the most space efficient manner
+ *
+ * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
+ */
+
+ var plFont = getPointLabelFontOptions(scale);
+
+ // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
+ // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
+ var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
+ var furthestLimits = {
+ r: scale.width,
+ l: 0,
+ t: scale.height,
+ b: 0
+ };
+ var furthestAngles = {};
+ var i;
+ var textSize;
+ var pointPosition;
+
+ scale.ctx.font = plFont.font;
+ scale._pointLabelSizes = [];
+
+ var valueCount = getValueCount(scale);
+ for (i = 0; i < valueCount; i++) {
+ pointPosition = scale.getPointPosition(i, largestPossibleRadius);
+ textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
+ scale._pointLabelSizes[i] = textSize;
+
+ // Add quarter circle to make degree 0 mean top of circle
+ var angleRadians = scale.getIndexAngle(i);
+ var angle = helpers.toDegrees(angleRadians) % 360;
+ var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
+ var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
+
+ if (hLimits.start < furthestLimits.l) {
+ furthestLimits.l = hLimits.start;
+ furthestAngles.l = angleRadians;
+ }
+
+ if (hLimits.end > furthestLimits.r) {
+ furthestLimits.r = hLimits.end;
+ furthestAngles.r = angleRadians;
+ }
+
+ if (vLimits.start < furthestLimits.t) {
+ furthestLimits.t = vLimits.start;
+ furthestAngles.t = angleRadians;
+ }
+
+ if (vLimits.end > furthestLimits.b) {
+ furthestLimits.b = vLimits.end;
+ furthestAngles.b = angleRadians;
+ }
+ }
+
+ scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
+ }
+
+ /**
+ * Helper function to fit a radial linear scale with no point labels
+ */
+ function fit(scale) {
+ var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
+ scale.drawingArea = Math.round(largestPossibleRadius);
+ scale.setCenterPoint(0, 0, 0, 0);
+ }
+
+ function getTextAlignForAngle(angle) {
+ if (angle === 0 || angle === 180) {
+ return 'center';
+ } else if (angle < 180) {
+ return 'left';
+ }
+
+ return 'right';
+ }
+
+ function fillText(ctx, text, position, fontSize) {
+ if (helpers.isArray(text)) {
+ var y = position.y;
+ var spacing = 1.5 * fontSize;
+
+ for (var i = 0; i < text.length; ++i) {
+ ctx.fillText(text[i], position.x, y);
+ y+= spacing;
+ }
+ } else {
+ ctx.fillText(text, position.x, position.y);
+ }
+ }
+
+ function adjustPointPositionForLabelHeight(angle, textSize, position) {
+ if (angle === 90 || angle === 270) {
+ position.y -= (textSize.h / 2);
+ } else if (angle > 270 || angle < 90) {
+ position.y -= textSize.h;
+ }
+ }
+
+ function drawPointLabels(scale) {
+ var ctx = scale.ctx;
+ var getValueOrDefault = helpers.getValueOrDefault;
+ var opts = scale.options;
+ var angleLineOpts = opts.angleLines;
+ var pointLabelOpts = opts.pointLabels;
+
+ ctx.lineWidth = angleLineOpts.lineWidth;
+ ctx.strokeStyle = angleLineOpts.color;
+
+ var outerDistance = scale.getDistanceFromCenterForValue(opts.reverse ? scale.min : scale.max);
+
+ // Point Label Font
+ var plFont = getPointLabelFontOptions(scale);
+
+ ctx.textBaseline = 'top';
+
+ for (var i = getValueCount(scale) - 1; i >= 0; i--) {
+ if (angleLineOpts.display) {
+ var outerPosition = scale.getPointPosition(i, outerDistance);
+ ctx.beginPath();
+ ctx.moveTo(scale.xCenter, scale.yCenter);
+ ctx.lineTo(outerPosition.x, outerPosition.y);
+ ctx.stroke();
+ ctx.closePath();
+ }
+
+ if (pointLabelOpts.display) {
+ // Extra 3px out for some label spacing
+ var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
+
+ // Keep this in loop since we may support array properties here
+ var pointLabelFontColor = getValueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor);
+ ctx.font = plFont.font;
+ ctx.fillStyle = pointLabelFontColor;
+
+ var angleRadians = scale.getIndexAngle(i);
+ var angle = helpers.toDegrees(angleRadians);
+ ctx.textAlign = getTextAlignForAngle(angle);
+ adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
+ fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
+ }
+ }
+ }
+
+ function drawRadiusLine(scale, gridLineOpts, radius, index) {
+ var ctx = scale.ctx;
+ ctx.strokeStyle = helpers.getValueAtIndexOrDefault(gridLineOpts.color, index - 1);
+ ctx.lineWidth = helpers.getValueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
+
+ if (scale.options.gridLines.circular) {
+ // Draw circular arcs between the points
+ ctx.beginPath();
+ ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
+ ctx.closePath();
+ ctx.stroke();
+ } else {
+ // Draw straight lines connecting each index
+ var valueCount = getValueCount(scale);
+
+ if (valueCount === 0) {
+ return;
+ }
+
+ ctx.beginPath();
+ var pointPosition = scale.getPointPosition(0, radius);
+ ctx.moveTo(pointPosition.x, pointPosition.y);
+
+ for (var i = 1; i < valueCount; i++) {
+ pointPosition = scale.getPointPosition(i, radius);
+ ctx.lineTo(pointPosition.x, pointPosition.y);
+ }
+
+ ctx.closePath();
+ ctx.stroke();
+ }
+ }
+
+ function numberOrZero(param) {
+ return helpers.isNumber(param) ? param : 0;
+ }
+
+ var LinearRadialScale = Chart.LinearScaleBase.extend({
+ setDimensions: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+ // Set the unconstrained dimension before label rotation
+ me.width = me.maxWidth;
+ me.height = me.maxHeight;
+ me.xCenter = Math.round(me.width / 2);
+ me.yCenter = Math.round(me.height / 2);
+
+ var minSize = helpers.min([me.height, me.width]);
+ var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
+ me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
+ },
+ determineDataLimits: function() {
+ var me = this;
+ var chart = me.chart;
+ var min = Number.POSITIVE_INFINITY;
+ var max = Number.NEGATIVE_INFINITY;
+
+ helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
+ if (chart.isDatasetVisible(datasetIndex)) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ min = Math.min(value, min);
+ max = Math.max(value, max);
+ });
+ }
+ });
+
+ me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
+ me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
+
+ // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
+ me.handleTickRangeOptions();
+ },
+ getTickLimit: function() {
+ var tickOpts = this.options.ticks;
+ var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
+ return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
+ },
+ convertTicksToLabels: function() {
+ var me = this;
+ Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);
+
+ // Point labels
+ me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
+ },
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+ fit: function() {
+ if (this.options.pointLabels.display) {
+ fitWithPointLabels(this);
+ } else {
+ fit(this);
+ }
+ },
+ /**
+ * Set radius reductions and determine new radius and center point
+ * @private
+ */
+ setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
+ var me = this;
+ var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
+ var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
+ var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
+ var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
+
+ radiusReductionLeft = numberOrZero(radiusReductionLeft);
+ radiusReductionRight = numberOrZero(radiusReductionRight);
+ radiusReductionTop = numberOrZero(radiusReductionTop);
+ radiusReductionBottom = numberOrZero(radiusReductionBottom);
+
+ me.drawingArea = Math.min(
+ Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
+ Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
+ me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
+ },
+ setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
+ var me = this;
+ var maxRight = me.width - rightMovement - me.drawingArea,
+ maxLeft = leftMovement + me.drawingArea,
+ maxTop = topMovement + me.drawingArea,
+ maxBottom = me.height - bottomMovement - me.drawingArea;
+
+ me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
+ me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
+ },
+
+ getIndexAngle: function(index) {
+ var angleMultiplier = (Math.PI * 2) / getValueCount(this);
+ var startAngle = this.chart.options && this.chart.options.startAngle ?
+ this.chart.options.startAngle :
+ 0;
+
+ var startAngleRadians = startAngle * Math.PI * 2 / 360;
+
+ // Start from the top instead of right, so remove a quarter of the circle
+ return index * angleMultiplier + startAngleRadians;
+ },
+ getDistanceFromCenterForValue: function(value) {
+ var me = this;
+
+ if (value === null) {
+ return 0; // null always in center
+ }
+
+ // Take into account half font size + the yPadding of the top value
+ var scalingFactor = me.drawingArea / (me.max - me.min);
+ if (me.options.reverse) {
+ return (me.max - value) * scalingFactor;
+ }
+ return (value - me.min) * scalingFactor;
+ },
+ getPointPosition: function(index, distanceFromCenter) {
+ var me = this;
+ var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
+ return {
+ x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
+ y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
+ };
+ },
+ getPointPositionForValue: function(index, value) {
+ return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
+ },
+
+ getBasePosition: function() {
+ var me = this;
+ var min = me.min;
+ var max = me.max;
+
+ return me.getPointPositionForValue(0,
+ me.beginAtZero? 0:
+ min < 0 && max < 0? max :
+ min > 0 && max > 0? min :
+ 0);
+ },
+
+ draw: function() {
+ var me = this;
+ var opts = me.options;
+ var gridLineOpts = opts.gridLines;
+ var tickOpts = opts.ticks;
+ var getValueOrDefault = helpers.getValueOrDefault;
+
+ if (opts.display) {
+ var ctx = me.ctx;
+
+ // Tick Font
+ var tickFontSize = getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
+ var tickFontStyle = getValueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
+ var tickFontFamily = getValueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
+ var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
+
+ helpers.each(me.ticks, function(label, index) {
+ // Don't draw a centre value (if it is minimum)
+ if (index > 0 || opts.reverse) {
+ var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
+ var yHeight = me.yCenter - yCenterOffset;
+
+ // Draw circular lines around the scale
+ if (gridLineOpts.display && index !== 0) {
+ drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
+ }
+
+ if (tickOpts.display) {
+ var tickFontColor = getValueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
+ ctx.font = tickLabelFont;
+
+ if (tickOpts.showLabelBackdrop) {
+ var labelWidth = ctx.measureText(label).width;
+ ctx.fillStyle = tickOpts.backdropColor;
+ ctx.fillRect(
+ me.xCenter - labelWidth / 2 - tickOpts.backdropPaddingX,
+ yHeight - tickFontSize / 2 - tickOpts.backdropPaddingY,
+ labelWidth + tickOpts.backdropPaddingX * 2,
+ tickFontSize + tickOpts.backdropPaddingY * 2
+ );
+ }
+
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillStyle = tickFontColor;
+ ctx.fillText(label, me.xCenter, yHeight);
+ }
+ }
+ });
+
+ if (opts.angleLines.display || opts.pointLabels.display) {
+ drawPointLabels(me);
+ }
+ }
+ }
+ });
+ Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);
+
+};
+
+},{}],49:[function(require,module,exports){
+/* global window: false */
+'use strict';
+
+var moment = require(6);
+moment = typeof(moment) === 'function' ? moment : window.moment;
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ var interval = {
+ millisecond: {
+ size: 1,
+ steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
+ },
+ second: {
+ size: 1000,
+ steps: [1, 2, 5, 10, 30]
+ },
+ minute: {
+ size: 60000,
+ steps: [1, 2, 5, 10, 30]
+ },
+ hour: {
+ size: 3600000,
+ steps: [1, 2, 3, 6, 12]
+ },
+ day: {
+ size: 86400000,
+ steps: [1, 2, 5]
+ },
+ week: {
+ size: 604800000,
+ maxStep: 4
+ },
+ month: {
+ size: 2.628e9,
+ maxStep: 3
+ },
+ quarter: {
+ size: 7.884e9,
+ maxStep: 4
+ },
+ year: {
+ size: 3.154e10,
+ maxStep: false
+ }
+ };
+
+ var defaultConfig = {
+ position: 'bottom',
+
+ time: {
+ parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
+ format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
+ unit: false, // false == automatic or override with week, month, year, etc.
+ round: false, // none, or override with week, month, year, etc.
+ displayFormat: false, // DEPRECATED
+ isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
+ minUnit: 'millisecond',
+
+ // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
+ displayFormats: {
+ millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
+ second: 'h:mm:ss a', // 11:20:01 AM
+ minute: 'h:mm:ss a', // 11:20:01 AM
+ hour: 'MMM D, hA', // Sept 4, 5PM
+ day: 'll', // Sep 4 2015
+ week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
+ month: 'MMM YYYY', // Sept 2015
+ quarter: '[Q]Q - YYYY', // Q3
+ year: 'YYYY' // 2015
+ },
+ },
+ ticks: {
+ autoSkip: false
+ }
+ };
+
+ /**
+ * Helper function to parse time to a moment object
+ * @param axis {TimeAxis} the time axis
+ * @param label {Date|string|number|Moment} The thing to parse
+ * @return {Moment} parsed time
+ */
+ function parseTime(axis, label) {
+ var timeOpts = axis.options.time;
+ if (typeof timeOpts.parser === 'string') {
+ return moment(label, timeOpts.parser);
+ }
+ if (typeof timeOpts.parser === 'function') {
+ return timeOpts.parser(label);
+ }
+ if (typeof label.getMonth === 'function' || typeof label === 'number') {
+ // Date objects
+ return moment(label);
+ }
+ if (label.isValid && label.isValid()) {
+ // Moment support
+ return label;
+ }
+ var format = timeOpts.format;
+ if (typeof format !== 'string' && format.call) {
+ // Custom parsing (return an instance of moment)
+ console.warn('options.time.format is deprecated and replaced by options.time.parser.');
+ return format(label);
+ }
+ // Moment format parsing
+ return moment(label, format);
+ }
+
+ /**
+ * Figure out which is the best unit for the scale
+ * @param minUnit {String} minimum unit to use
+ * @param min {Number} scale minimum
+ * @param max {Number} scale maximum
+ * @return {String} the unit to use
+ */
+ function determineUnit(minUnit, min, max, maxTicks) {
+ var units = Object.keys(interval);
+ var unit;
+ var numUnits = units.length;
+
+ for (var i = units.indexOf(minUnit); i < numUnits; i++) {
+ unit = units[i];
+ var unitDetails = interval[unit];
+ var steps = (unitDetails.steps && unitDetails.steps[unitDetails.steps.length - 1]) || unitDetails.maxStep;
+ if (steps === undefined || Math.ceil((max - min) / (steps * unitDetails.size)) <= maxTicks) {
+ break;
+ }
+ }
+
+ return unit;
+ }
+
+ /**
+ * Determines how we scale the unit
+ * @param min {Number} the scale minimum
+ * @param max {Number} the scale maximum
+ * @param unit {String} the unit determined by the {@see determineUnit} method
+ * @return {Number} the axis step size as a multiple of unit
+ */
+ function determineStepSize(min, max, unit, maxTicks) {
+ // Using our unit, figoure out what we need to scale as
+ var unitDefinition = interval[unit];
+ var unitSizeInMilliSeconds = unitDefinition.size;
+ var sizeInUnits = Math.ceil((max - min) / unitSizeInMilliSeconds);
+ var multiplier = 1;
+ var range = max - min;
+
+ if (unitDefinition.steps) {
+ // Have an array of steps
+ var numSteps = unitDefinition.steps.length;
+ for (var i = 0; i < numSteps && sizeInUnits > maxTicks; i++) {
+ multiplier = unitDefinition.steps[i];
+ sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
+ }
+ } else {
+ while (sizeInUnits > maxTicks && maxTicks > 0) {
+ ++multiplier;
+ sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
+ }
+ }
+
+ return multiplier;
+ }
+
+ /**
+ * Helper for generating axis labels.
+ * @param options {ITimeGeneratorOptions} the options for generation
+ * @param dataRange {IRange} the data range
+ * @param niceRange {IRange} the pretty range to display
+ * @return {Number[]} ticks
+ */
+ function generateTicks(options, dataRange, niceRange) {
+ var ticks = [];
+ if (options.maxTicks) {
+ var stepSize = options.stepSize;
+ ticks.push(options.min !== undefined ? options.min : niceRange.min);
+ var cur = moment(niceRange.min);
+ while (cur.add(stepSize, options.unit).valueOf() < niceRange.max) {
+ ticks.push(cur.valueOf());
+ }
+ var realMax = options.max || niceRange.max;
+ if (ticks[ticks.length - 1] !== realMax) {
+ ticks.push(realMax);
+ }
+ }
+ return ticks;
+ }
+
+ /**
+ * @function Chart.Ticks.generators.time
+ * @param options {ITimeGeneratorOptions} the options for generation
+ * @param dataRange {IRange} the data range
+ * @return {Number[]} ticks
+ */
+ Chart.Ticks.generators.time = function(options, dataRange) {
+ var niceMin;
+ var niceMax;
+ var isoWeekday = options.isoWeekday;
+ if (options.unit === 'week' && isoWeekday !== false) {
+ niceMin = moment(dataRange.min).startOf('isoWeek').isoWeekday(isoWeekday).valueOf();
+ niceMax = moment(dataRange.max).startOf('isoWeek').isoWeekday(isoWeekday);
+ if (dataRange.max - niceMax > 0) {
+ niceMax.add(1, 'week');
+ }
+ niceMax = niceMax.valueOf();
+ } else {
+ niceMin = moment(dataRange.min).startOf(options.unit).valueOf();
+ niceMax = moment(dataRange.max).startOf(options.unit);
+ if (dataRange.max - niceMax > 0) {
+ niceMax.add(1, options.unit);
+ }
+ niceMax = niceMax.valueOf();
+ }
+ return generateTicks(options, dataRange, {
+ min: niceMin,
+ max: niceMax
+ });
+ };
+
+ var TimeScale = Chart.Scale.extend({
+ initialize: function() {
+ if (!moment) {
+ throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
+ }
+
+ Chart.Scale.prototype.initialize.call(this);
+ },
+ determineDataLimits: function() {
+ var me = this;
+ var timeOpts = me.options.time;
+
+ // We store the data range as unix millisecond timestamps so dataMin and dataMax will always be integers.
+ var dataMin = Number.MAX_SAFE_INTEGER;
+ var dataMax = Number.MIN_SAFE_INTEGER;
+
+ var chartData = me.chart.data;
+ var parsedData = {
+ labels: [],
+ datasets: []
+ };
+
+ var timestamp;
+
+ helpers.each(chartData.labels, function(label, labelIndex) {
+ var labelMoment = parseTime(me, label);
+
+ if (labelMoment.isValid()) {
+ // We need to round the time
+ if (timeOpts.round) {
+ labelMoment.startOf(timeOpts.round);
+ }
+
+ timestamp = labelMoment.valueOf();
+ dataMin = Math.min(timestamp, dataMin);
+ dataMax = Math.max(timestamp, dataMax);
+
+ // Store this value for later
+ parsedData.labels[labelIndex] = timestamp;
+ }
+ });
+
+ helpers.each(chartData.datasets, function(dataset, datasetIndex) {
+ var timestamps = [];
+
+ if (typeof dataset.data[0] === 'object' && dataset.data[0] !== null && me.chart.isDatasetVisible(datasetIndex)) {
+ // We have potential point data, so we need to parse this
+ helpers.each(dataset.data, function(value, dataIndex) {
+ var dataMoment = parseTime(me, me.getRightValue(value));
+
+ if (dataMoment.isValid()) {
+ if (timeOpts.round) {
+ dataMoment.startOf(timeOpts.round);
+ }
+
+ timestamp = dataMoment.valueOf();
+ dataMin = Math.min(timestamp, dataMin);
+ dataMax = Math.max(timestamp, dataMax);
+ timestamps[dataIndex] = timestamp;
+ }
+ });
+ } else {
+ // We have no x coordinates, so use the ones from the labels
+ timestamps = parsedData.labels.slice();
+ }
+
+ parsedData.datasets[datasetIndex] = timestamps;
+ });
+
+ me.dataMin = dataMin;
+ me.dataMax = dataMax;
+ me._parsedData = parsedData;
+ },
+ buildTicks: function() {
+ var me = this;
+ var timeOpts = me.options.time;
+
+ var minTimestamp;
+ var maxTimestamp;
+ var dataMin = me.dataMin;
+ var dataMax = me.dataMax;
+
+ if (timeOpts.min) {
+ var minMoment = parseTime(me, timeOpts.min);
+ if (timeOpts.round) {
+ minMoment.round(timeOpts.round);
+ }
+ minTimestamp = minMoment.valueOf();
+ }
+
+ if (timeOpts.max) {
+ maxTimestamp = parseTime(me, timeOpts.max).valueOf();
+ }
+
+ var maxTicks = me.getLabelCapacity(minTimestamp || dataMin);
+ var unit = timeOpts.unit || determineUnit(timeOpts.minUnit, minTimestamp || dataMin, maxTimestamp || dataMax, maxTicks);
+ me.displayFormat = timeOpts.displayFormats[unit];
+
+ var stepSize = timeOpts.stepSize || determineStepSize(minTimestamp || dataMin, maxTimestamp || dataMax, unit, maxTicks);
+ me.ticks = Chart.Ticks.generators.time({
+ maxTicks: maxTicks,
+ min: minTimestamp,
+ max: maxTimestamp,
+ stepSize: stepSize,
+ unit: unit,
+ isoWeekday: timeOpts.isoWeekday
+ }, {
+ min: dataMin,
+ max: dataMax
+ });
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ me.max = helpers.max(me.ticks);
+ me.min = helpers.min(me.ticks);
+ },
+ // Get tooltip label
+ getLabelForIndex: function(index, datasetIndex) {
+ var me = this;
+ var label = me.chart.data.labels && index < me.chart.data.labels.length ? me.chart.data.labels[index] : '';
+ var value = me.chart.data.datasets[datasetIndex].data[index];
+
+ if (value !== null && typeof value === 'object') {
+ label = me.getRightValue(value);
+ }
+
+ // Format nicely
+ if (me.options.time.tooltipFormat) {
+ label = parseTime(me, label).format(me.options.time.tooltipFormat);
+ }
+
+ return label;
+ },
+ // Function to format an individual tick mark
+ tickFormatFunction: function(tick, index, ticks) {
+ var formattedTick = tick.format(this.displayFormat);
+ var tickOpts = this.options.ticks;
+ var callback = helpers.getValueOrDefault(tickOpts.callback, tickOpts.userCallback);
+
+ if (callback) {
+ return callback(formattedTick, index, ticks);
+ }
+ return formattedTick;
+ },
+ convertTicksToLabels: function() {
+ var me = this;
+ me.ticksAsTimestamps = me.ticks;
+ me.ticks = me.ticks.map(function(tick) {
+ return moment(tick);
+ }).map(me.tickFormatFunction, me);
+ },
+ getPixelForOffset: function(offset) {
+ var me = this;
+ var epochWidth = me.max - me.min;
+ var decimal = epochWidth ? (offset - me.min) / epochWidth : 0;
+
+ if (me.isHorizontal()) {
+ var valueOffset = (me.width * decimal);
+ return me.left + Math.round(valueOffset);
+ }
+
+ var heightOffset = (me.height * decimal);
+ return me.top + Math.round(heightOffset);
+ },
+ getPixelForValue: function(value, index, datasetIndex) {
+ var me = this;
+ var offset = null;
+ if (index !== undefined && datasetIndex !== undefined) {
+ offset = me._parsedData.datasets[datasetIndex][index];
+ }
+
+ if (offset === null) {
+ if (!value || !value.isValid) {
+ // not already a moment object
+ value = parseTime(me, me.getRightValue(value));
+ }
+
+ if (value && value.isValid && value.isValid()) {
+ offset = value.valueOf();
+ }
+ }
+
+ if (offset !== null) {
+ return me.getPixelForOffset(offset);
+ }
+ },
+ getPixelForTick: function(index) {
+ return this.getPixelForOffset(this.ticksAsTimestamps[index]);
+ },
+ getValueForPixel: function(pixel) {
+ var me = this;
+ var innerDimension = me.isHorizontal() ? me.width : me.height;
+ var offset = (pixel - (me.isHorizontal() ? me.left : me.top)) / innerDimension;
+ return moment(me.min + (offset * (me.max - me.min)));
+ },
+ // Crude approximation of what the label width might be
+ getLabelWidth: function(label) {
+ var me = this;
+ var ticks = me.options.ticks;
+
+ var tickLabelWidth = me.ctx.measureText(label).width;
+ var cosRotation = Math.cos(helpers.toRadians(ticks.maxRotation));
+ var sinRotation = Math.sin(helpers.toRadians(ticks.maxRotation));
+ var tickFontSize = helpers.getValueOrDefault(ticks.fontSize, Chart.defaults.global.defaultFontSize);
+ return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
+ },
+ getLabelCapacity: function(exampleTime) {
+ var me = this;
+
+ me.displayFormat = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
+ var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, []);
+ var tickLabelWidth = me.getLabelWidth(exampleLabel);
+
+ var innerWidth = me.isHorizontal() ? me.width : me.height;
+ var labelCapacity = innerWidth / tickLabelWidth;
+ return labelCapacity;
+ }
+ });
+ Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig);
+
+};
+
+},{"6":6}]},{},[7])(7)
+});
\ No newline at end of file
diff --git a/contao/assets/chartjs/dist/Chart.bundle.min.js b/contao/assets/chartjs/dist/Chart.bundle.min.js
new file mode 100644
index 0000000..a7c0cf9
--- /dev/null
+++ b/contao/assets/chartjs/dist/Chart.bundle.min.js
@@ -0,0 +1,16 @@
+/*!
+ * Chart.js
+ * http://chartjs.org/
+ * Version: 2.6.0
+ *
+ * Copyright 2017 Nick Downie
+ * Released under the MIT license
+ * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
+ */
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Chart=t()}}(function(){var t;return function t(e,n,i){function a(o,s){if(!n[o]){if(!e[o]){var l="function"==typeof require&&require;if(!s&&l)return l(o,!0);if(r)return r(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var d=n[o]={exports:{}};e[o][0].call(d.exports,function(t){var n=e[o][1][t];return a(n?n:t)},d,d.exports,t,e,n,i)}return n[o].exports}for(var r="function"==typeof require&&require,o=0;on?(e+.05)/(n+.05):(n+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb,e=(299*t[0]+587*t[1]+114*t[2])/1e3;return e<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,n=(e[0]+t)%360;return e[0]=n<0?360+n:n,this.setValues("hsl",e),this},mix:function(t,e){var n=this,i=t,a=void 0===e?.5:e,r=2*a-1,o=n.alpha()-i.alpha(),s=((r*o===-1?r:(r+o)/(1+r*o))+1)/2,l=1-s;return this.rgb(s*n.red()+l*i.red(),s*n.green()+l*i.green(),s*n.blue()+l*i.blue()).alpha(n.alpha()*a+i.alpha()*(1-a))},toJSON:function(){return this.rgb()},clone:function(){var t,e,n=new r,i=this.values,a=n.values;for(var o in i)i.hasOwnProperty(o)&&(t=i[o],e={}.toString.call(t),"[object Array]"===e?a[o]=t.slice(0):"[object Number]"===e?a[o]=t:console.error("unexpected color value:",t));return n}},r.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},r.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},r.prototype.getValues=function(t){for(var e=this.values,n={},i=0;i.04045?Math.pow((e+.055)/1.055,2.4):e/12.92,n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92,i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92;var a=.4124*e+.3576*n+.1805*i,r=.2126*e+.7152*n+.0722*i,o=.0193*e+.1192*n+.9505*i;return[100*a,100*r,100*o]}function d(t){var e,n,i,a=u(t),r=a[0],o=a[1],s=a[2];return r/=95.047,o/=100,s/=108.883,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116,e=116*o-16,n=500*(r-o),i=200*(o-s),[e,n,i]}function c(t){return Y(d(t))}function h(t){var e,n,i,a,r,o=t[0]/360,s=t[1]/100,l=t[2]/100;if(0==s)return r=255*l,[r,r,r];n=l<.5?l*(1+s):l+s-l*s,e=2*l-n,a=[0,0,0];for(var u=0;u<3;u++)i=o+1/3*-(u-1),i<0&&i++,i>1&&i--,r=6*i<1?e+6*(n-e)*i:2*i<1?n:3*i<2?e+(n-e)*(2/3-i)*6:e,a[u]=255*r;return a}function f(t){var e,n,i=t[0],a=t[1]/100,r=t[2]/100;return 0===r?[0,0,0]:(r*=2,a*=r<=1?r:2-r,n=(r+a)/2,e=2*a/(r+a),[i,100*e,100*n])}function p(t){return o(h(t))}function m(t){return s(h(t))}function v(t){return l(h(t))}function y(t){var e=t[0]/60,n=t[1]/100,i=t[2]/100,a=Math.floor(e)%6,r=e-Math.floor(e),o=255*i*(1-n),s=255*i*(1-n*r),l=255*i*(1-n*(1-r)),i=255*i;switch(a){case 0:return[i,l,o];case 1:return[s,i,o];case 2:return[o,i,l];case 3:return[o,s,i];case 4:return[l,o,i];case 5:return[i,o,s]}}function x(t){var e,n,i=t[0],a=t[1]/100,r=t[2]/100;return n=(2-a)*r,e=a*r,e/=n<=1?n:2-n,e=e||0,n/=2,[i,100*e,100*n]}function _(t){return o(y(t))}function k(t){return s(y(t))}function w(t){return l(y(t))}function M(t){var e,n,i,a,o=t[0]/360,s=t[1]/100,l=t[2]/100,u=s+l;switch(u>1&&(s/=u,l/=u),e=Math.floor(6*o),n=1-l,i=6*o-e,0!=(1&e)&&(i=1-i),a=s+i*(n-s),e){default:case 6:case 0:r=n,g=a,b=s;break;case 1:r=a,g=n,b=s;break;case 2:r=s,g=n,b=a;break;case 3:r=s,g=a,b=n;break;case 4:r=a,g=s,b=n;break;case 5:r=n,g=s,b=a}return[255*r,255*g,255*b]}function S(t){return i(M(t))}function D(t){return a(M(t))}function C(t){return s(M(t))}function P(t){return l(M(t))}function T(t){var e,n,i,a=t[0]/100,r=t[1]/100,o=t[2]/100,s=t[3]/100;return e=1-Math.min(1,a*(1-s)+s),n=1-Math.min(1,r*(1-s)+s),i=1-Math.min(1,o*(1-s)+s),[255*e,255*n,255*i]}function I(t){return i(T(t))}function A(t){return a(T(t))}function F(t){return o(T(t))}function O(t){return l(T(t))}function R(t){var e,n,i,a=t[0]/100,r=t[1]/100,o=t[2]/100;return e=3.2406*a+r*-1.5372+o*-.4986,n=a*-.9689+1.8758*r+.0415*o,i=.0557*a+r*-.204+1.057*o,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:e*=12.92,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,e=Math.min(Math.max(0,e),1),n=Math.min(Math.max(0,n),1),i=Math.min(Math.max(0,i),1),[255*e,255*n,255*i]}function L(t){var e,n,i,a=t[0],r=t[1],o=t[2];return a/=95.047,r/=100,o/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,e=116*r-16,n=500*(a-r),i=200*(r-o),[e,n,i]}function V(t){return Y(L(t))}function W(t){var e,n,i,a,r=t[0],o=t[1],s=t[2];return r<=8?(n=100*r/903.3,a=7.787*(n/100)+16/116):(n=100*Math.pow((r+16)/116,3),a=Math.pow(n/100,1/3)),e=e/95.047<=.008856?e=95.047*(o/500+a-16/116)/7.787:95.047*Math.pow(o/500+a,3),i=i/108.883<=.008859?i=108.883*(a-s/200-16/116)/7.787:108.883*Math.pow(a-s/200,3),[e,n,i]}function Y(t){var e,n,i,a=t[0],r=t[1],o=t[2];return e=Math.atan2(o,r),n=360*e/2/Math.PI,n<0&&(n+=360),i=Math.sqrt(r*r+o*o),[a,i,n]}function z(t){return R(W(t))}function N(t){var e,n,i,a=t[0],r=t[1],o=t[2];return i=o/360*2*Math.PI,e=r*Math.cos(i),n=r*Math.sin(i),[a,e,n]}function B(t){return W(N(t))}function E(t){return z(N(t))}function H(t){return J[t]}function j(t){return i(H(t))}function U(t){return a(H(t))}function G(t){return o(H(t))}function q(t){return s(H(t))}function Z(t){return d(H(t))}function X(t){return u(H(t))}e.exports={rgb2hsl:i,rgb2hsv:a,rgb2hwb:o,rgb2cmyk:s,rgb2keyword:l,rgb2xyz:u,rgb2lab:d,rgb2lch:c,hsl2rgb:h,hsl2hsv:f,hsl2hwb:p,hsl2cmyk:m,hsl2keyword:v,hsv2rgb:y,hsv2hsl:x,hsv2hwb:_,hsv2cmyk:k,hsv2keyword:w,hwb2rgb:M,hwb2hsl:S,hwb2hsv:D,hwb2cmyk:C,hwb2keyword:P,cmyk2rgb:T,cmyk2hsl:I,cmyk2hsv:A,cmyk2hwb:F,cmyk2keyword:O,keyword2rgb:H,keyword2hsl:j,keyword2hsv:U,keyword2hwb:G,keyword2cmyk:q,keyword2lab:Z,keyword2xyz:X,xyz2rgb:R,xyz2lab:L,xyz2lch:V,lab2xyz:W,lab2rgb:z,lab2lch:Y,lch2lab:N,lch2xyz:B,lch2rgb:E};var J={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]},K={};for(var Q in J)K[JSON.stringify(J[Q])]=Q},{}],4:[function(t,e,n){var i=t(3),a=function(){return new u};for(var r in i){a[r+"Raw"]=function(t){return function(e){return"number"==typeof e&&(e=Array.prototype.slice.call(arguments)),i[t](e)}}(r);var o=/(\w+)2(\w+)/.exec(r),s=o[1],l=o[2];a[s]=a[s]||{},a[s][l]=a[r]=function(t){return function(e){"number"==typeof e&&(e=Array.prototype.slice.call(arguments));var n=i[t](e);if("string"==typeof n||void 0===n)return n;for(var a=0;a0)for(n=0;n0?"future":"past"];return C(n)?n(e):n.replace(/%s/i,e)}function W(t,e){var n=t.toLowerCase();Vi[n]=Vi[n+"s"]=Vi[e]=t}function Y(t){return"string"==typeof t?Vi[t]||Vi[t.toLowerCase()]:void 0}function z(t){var e,n,i={};for(n in t)c(t,n)&&(e=Y(n),e&&(i[e]=t[n]));return i}function N(t,e){Wi[t]=e}function B(t){var e=[];for(var n in t)e.push({unit:n,priority:Wi[n]});return e.sort(function(t,e){return t.priority-e.priority}),e}function E(e,n){return function(i){return null!=i?(j(this,e,i),t.updateOffset(this,n),this):H(this,e)}}function H(t,e){return t.isValid()?t._d["get"+(t._isUTC?"UTC":"")+e]():NaN}function j(t,e,n){t.isValid()&&t._d["set"+(t._isUTC?"UTC":"")+e](n)}function U(t){return t=Y(t),C(this[t])?this[t]():this}function G(t,e){if("object"==typeof t){t=z(t);for(var n=B(t),i=0;i=0;return(r?n?"+":"":"-")+Math.pow(10,Math.max(0,a)).toString().substr(1)+i}function Z(t,e,n,i){var a=i;"string"==typeof i&&(a=function(){return this[i]()}),t&&(Bi[t]=a),e&&(Bi[e[0]]=function(){return q(a.apply(this,arguments),e[1],e[2])}),n&&(Bi[n]=function(){return this.localeData().ordinal(a.apply(this,arguments),t)})}function X(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function J(t){var e,n,i=t.match(Yi);for(e=0,n=i.length;e=0&&zi.test(t);)t=t.replace(zi,n),zi.lastIndex=0,i-=1;return t}function $(t,e,n){ra[t]=C(e)?e:function(t,i){return t&&n?n:e}}function tt(t,e){return c(ra,t)?ra[t](e._strict,e._locale):new RegExp(et(t))}function et(t){return nt(t.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,n,i,a){return e||n||i||a}))}function nt(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function it(t,e){var n,i=e;for("string"==typeof t&&(t=[t]),l(e)&&(i=function(t,n){n[e]=k(t)}),n=0;n=0&&isFinite(s.getFullYear())&&s.setFullYear(t),s}function _t(t){var e=new Date(Date.UTC.apply(null,arguments));return t<100&&t>=0&&isFinite(e.getUTCFullYear())&&e.setUTCFullYear(t),e}function kt(t,e,n){var i=7+e-n,a=(7+_t(t,0,i).getUTCDay()-e)%7;return-a+i-1}function wt(t,e,n,i,a){var r,o,s=(7+n-i)%7,l=kt(t,i,a),u=1+7*(e-1)+s+l;return u<=0?(r=t-1,o=vt(r)+u):u>vt(t)?(r=t+1,o=u-vt(t)):(r=t,o=u),{year:r,dayOfYear:o}}function Mt(t,e,n){var i,a,r=kt(t.year(),e,n),o=Math.floor((t.dayOfYear()-r-1)/7)+1;return o<1?(a=t.year()-1,i=o+St(a,e,n)):o>St(t.year(),e,n)?(i=o-St(t.year(),e,n),a=t.year()+1):(a=t.year(),i=o),{week:i,year:a}}function St(t,e,n){var i=kt(t,e,n),a=kt(t+1,e,n);return(vt(t)-i+a)/7}function Dt(t){return Mt(t,this._week.dow,this._week.doy).week}function Ct(){return this._week.dow}function Pt(){return this._week.doy}function Tt(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")}function It(t){var e=Mt(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")}function At(t,e){return"string"!=typeof t?t:isNaN(t)?(t=e.weekdaysParse(t),"number"==typeof t?t:null):parseInt(t,10)}function Ft(t,e){return"string"==typeof t?e.weekdaysParse(t)%7||7:isNaN(t)?null:t}function Ot(t,e){return t?a(this._weekdays)?this._weekdays[t.day()]:this._weekdays[this._weekdays.isFormat.test(e)?"format":"standalone"][t.day()]:a(this._weekdays)?this._weekdays:this._weekdays.standalone}function Rt(t){return t?this._weekdaysShort[t.day()]:this._weekdaysShort}function Lt(t){return t?this._weekdaysMin[t.day()]:this._weekdaysMin}function Vt(t,e,n){var i,a,r,o=t.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],i=0;i<7;++i)r=f([2e3,1]).day(i),this._minWeekdaysParse[i]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[i]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[i]=this.weekdays(r,"").toLocaleLowerCase();return n?"dddd"===e?(a=ma.call(this._weekdaysParse,o),a!==-1?a:null):"ddd"===e?(a=ma.call(this._shortWeekdaysParse,o),a!==-1?a:null):(a=ma.call(this._minWeekdaysParse,o),a!==-1?a:null):"dddd"===e?(a=ma.call(this._weekdaysParse,o),a!==-1?a:(a=ma.call(this._shortWeekdaysParse,o),a!==-1?a:(a=ma.call(this._minWeekdaysParse,o),a!==-1?a:null))):"ddd"===e?(a=ma.call(this._shortWeekdaysParse,o),a!==-1?a:(a=ma.call(this._weekdaysParse,o),a!==-1?a:(a=ma.call(this._minWeekdaysParse,o),a!==-1?a:null))):(a=ma.call(this._minWeekdaysParse,o),a!==-1?a:(a=ma.call(this._weekdaysParse,o),a!==-1?a:(a=ma.call(this._shortWeekdaysParse,o),a!==-1?a:null)))}function Wt(t,e,n){var i,a,r;if(this._weekdaysParseExact)return Vt.call(this,t,e,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),i=0;i<7;i++){if(a=f([2e3,1]).day(i),n&&!this._fullWeekdaysParse[i]&&(this._fullWeekdaysParse[i]=new RegExp("^"+this.weekdays(a,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[i]=new RegExp("^"+this.weekdaysShort(a,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[i]=new RegExp("^"+this.weekdaysMin(a,"").replace(".",".?")+"$","i")),this._weekdaysParse[i]||(r="^"+this.weekdays(a,"")+"|^"+this.weekdaysShort(a,"")+"|^"+this.weekdaysMin(a,""),this._weekdaysParse[i]=new RegExp(r.replace(".",""),"i")),n&&"dddd"===e&&this._fullWeekdaysParse[i].test(t))return i;if(n&&"ddd"===e&&this._shortWeekdaysParse[i].test(t))return i;if(n&&"dd"===e&&this._minWeekdaysParse[i].test(t))return i;if(!n&&this._weekdaysParse[i].test(t))return i}}function Yt(t){if(!this.isValid())return null!=t?this:NaN;var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=At(t,this.localeData()),this.add(t-e,"d")):e}function zt(t){if(!this.isValid())return null!=t?this:NaN;var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")}function Nt(t){if(!this.isValid())return null!=t?this:NaN;if(null!=t){var e=Ft(t,this.localeData());return this.day(this.day()%7?e:e-7)}return this.day()||7}function Bt(t){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||jt.call(this),t?this._weekdaysStrictRegex:this._weekdaysRegex):(c(this,"_weekdaysRegex")||(this._weekdaysRegex=Ca),this._weekdaysStrictRegex&&t?this._weekdaysStrictRegex:this._weekdaysRegex)}function Et(t){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||jt.call(this),t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(c(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Pa),this._weekdaysShortStrictRegex&&t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Ht(t){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||jt.call(this),t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(c(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Ta),this._weekdaysMinStrictRegex&&t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function jt(){function t(t,e){return e.length-t.length}var e,n,i,a,r,o=[],s=[],l=[],u=[];for(e=0;e<7;e++)n=f([2e3,1]).day(e),i=this.weekdaysMin(n,""),a=this.weekdaysShort(n,""),r=this.weekdays(n,""),o.push(i),s.push(a),l.push(r),u.push(i),u.push(a),u.push(r);for(o.sort(t),s.sort(t),l.sort(t),u.sort(t),e=0;e<7;e++)s[e]=nt(s[e]),l[e]=nt(l[e]),u[e]=nt(u[e]);this._weekdaysRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+o.join("|")+")","i")}function Ut(){return this.hours()%12||12}function Gt(){return this.hours()||24}function qt(t,e){Z(t,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)})}function Zt(t,e){return e._meridiemParse}function Xt(t){return"p"===(t+"").toLowerCase().charAt(0)}function Jt(t,e,n){return t>11?n?"pm":"PM":n?"am":"AM"}function Kt(t){return t?t.toLowerCase().replace("_","-"):t}function Qt(t){for(var e,n,i,a,r=0;r0;){if(i=$t(a.slice(0,e).join("-")))return i;if(n&&n.length>=e&&w(a,n,!0)>=e-1)break;e--}r++}return null}function $t(t){var i=null;if(!Ra[t]&&"undefined"!=typeof n&&n&&n.exports)try{i=Ia._abbr,e("./locale/"+t),te(i)}catch(t){}return Ra[t]}function te(t,e){var n;return t&&(n=s(e)?ie(t):ee(t,e),n&&(Ia=n)),Ia._abbr}function ee(t,e){if(null!==e){var n=Oa;if(e.abbr=t,null!=Ra[t])D("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),n=Ra[t]._config;else if(null!=e.parentLocale){if(null==Ra[e.parentLocale])return La[e.parentLocale]||(La[e.parentLocale]=[]),La[e.parentLocale].push({name:t,config:e}),null;n=Ra[e.parentLocale]._config}return Ra[t]=new I(T(n,e)),La[t]&&La[t].forEach(function(t){ee(t.name,t.config)}),te(t),Ra[t]}return delete Ra[t],null}function ne(t,e){if(null!=e){var n,i=Oa;null!=Ra[t]&&(i=Ra[t]._config),e=T(i,e),n=new I(e),n.parentLocale=Ra[t],Ra[t]=n,te(t)}else null!=Ra[t]&&(null!=Ra[t].parentLocale?Ra[t]=Ra[t].parentLocale:null!=Ra[t]&&delete Ra[t]);return Ra[t]}function ie(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Ia;if(!a(t)){if(e=$t(t))return e;t=[t]}return Qt(t)}function ae(){return Ti(Ra)}function re(t){var e,n=t._a;return n&&p(t).overflow===-2&&(e=n[la]<0||n[la]>11?la:n[ua]<1||n[ua]>ot(n[sa],n[la])?ua:n[da]<0||n[da]>24||24===n[da]&&(0!==n[ca]||0!==n[ha]||0!==n[fa])?da:n[ca]<0||n[ca]>59?ca:n[ha]<0||n[ha]>59?ha:n[fa]<0||n[fa]>999?fa:-1,p(t)._overflowDayOfYear&&(eua)&&(e=ua),p(t)._overflowWeeks&&e===-1&&(e=ga),p(t)._overflowWeekday&&e===-1&&(e=pa),p(t).overflow=e),t}function oe(t){var e,n,i,a,r,o,s=t._i,l=Va.exec(s)||Wa.exec(s);if(l){for(p(t).iso=!0,e=0,n=za.length;e10?"YYYY ":"YY "),r="HH:mm"+(n[4]?":ss":""),n[1]){var c=new Date(n[2]),h=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][c.getDay()];if(n[1].substr(0,3)!==h)return p(t).weekdayMismatch=!0,void(t._isValid=!1)}switch(n[5].length){case 2:0===l?s=" +0000":(l=d.indexOf(n[5][1].toUpperCase())-12,s=(l<0?" -":" +")+(""+l).replace(/^-?/,"0").match(/..$/)[0]+"00");break;case 4:s=u[n[5]];break;default:s=u[" GMT"]}n[5]=s,t._i=n.splice(1).join(""),o=" ZZ",t._f=i+a+r+o,fe(t),p(t).rfc2822=!0}else t._isValid=!1}function le(e){var n=Ba.exec(e._i);return null!==n?void(e._d=new Date(+n[1])):(oe(e),void(e._isValid===!1&&(delete e._isValid,se(e),e._isValid===!1&&(delete e._isValid,t.createFromInputFallback(e)))))}function ue(t,e,n){return null!=t?t:null!=e?e:n}function de(e){var n=new Date(t.now());return e._useUTC?[n.getUTCFullYear(),n.getUTCMonth(),n.getUTCDate()]:[n.getFullYear(),n.getMonth(),n.getDate()]}function ce(t){var e,n,i,a,r=[];if(!t._d){for(i=de(t),t._w&&null==t._a[ua]&&null==t._a[la]&&he(t),null!=t._dayOfYear&&(a=ue(t._a[sa],i[sa]),(t._dayOfYear>vt(a)||0===t._dayOfYear)&&(p(t)._overflowDayOfYear=!0),n=_t(a,0,t._dayOfYear),t._a[la]=n.getUTCMonth(),t._a[ua]=n.getUTCDate()),e=0;e<3&&null==t._a[e];++e)t._a[e]=r[e]=i[e];for(;e<7;e++)t._a[e]=r[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[da]&&0===t._a[ca]&&0===t._a[ha]&&0===t._a[fa]&&(t._nextDay=!0,t._a[da]=0),t._d=(t._useUTC?_t:xt).apply(null,r),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[da]=24)}}function he(t){var e,n,i,a,r,o,s,l;if(e=t._w,null!=e.GG||null!=e.W||null!=e.E)r=1,o=4,n=ue(e.GG,t._a[sa],Mt(_e(),1,4).year),i=ue(e.W,1),a=ue(e.E,1),(a<1||a>7)&&(l=!0);else{r=t._locale._week.dow,o=t._locale._week.doy;var u=Mt(_e(),r,o);n=ue(e.gg,t._a[sa],u.year),i=ue(e.w,u.week),null!=e.d?(a=e.d,(a<0||a>6)&&(l=!0)):null!=e.e?(a=e.e+r,(e.e<0||e.e>6)&&(l=!0)):a=r}i<1||i>St(n,r,o)?p(t)._overflowWeeks=!0:null!=l?p(t)._overflowWeekday=!0:(s=wt(n,i,a,r,o),t._a[sa]=s.year,t._dayOfYear=s.dayOfYear)}function fe(e){if(e._f===t.ISO_8601)return void oe(e);if(e._f===t.RFC_2822)return void se(e);e._a=[],p(e).empty=!0;var n,i,a,r,o,s=""+e._i,l=s.length,u=0;for(a=Q(e._f,e._locale).match(Yi)||[],n=0;n0&&p(e).unusedInput.push(o),s=s.slice(s.indexOf(i)+i.length),u+=i.length),Bi[r]?(i?p(e).empty=!1:p(e).unusedTokens.push(r),rt(r,i,e)):e._strict&&!i&&p(e).unusedTokens.push(r);p(e).charsLeftOver=l-u,s.length>0&&p(e).unusedInput.push(s),e._a[da]<=12&&p(e).bigHour===!0&&e._a[da]>0&&(p(e).bigHour=void 0),p(e).parsedDateParts=e._a.slice(0),p(e).meridiem=e._meridiem,e._a[da]=ge(e._locale,e._a[da],e._meridiem),ce(e),re(e)}function ge(t,e,n){var i;return null==n?e:null!=t.meridiemHour?t.meridiemHour(e,n):null!=t.isPM?(i=t.isPM(n),i&&e<12&&(e+=12),i||12!==e||(e=0),e):e}function pe(t){var e,n,i,a,r;if(0===t._f.length)return p(t).invalidFormat=!0,void(t._d=new Date(NaN));for(a=0;athis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ee(){if(!s(this._isDSTShifted))return this._isDSTShifted;var t={};if(y(t,this),t=ye(t),t._a){var e=t._isUTC?f(t._a):_e(t._a);this._isDSTShifted=this.isValid()&&w(t._a,e.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function He(){return!!this.isValid()&&!this._isUTC}function je(){return!!this.isValid()&&this._isUTC}function Ue(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Ge(t,e){var n,i,a,r=t,o=null;return Te(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:l(t)?(r={},e?r[e]=t:r.milliseconds=t):(o=Za.exec(t))?(n="-"===o[1]?-1:1,r={y:0,d:k(o[ua])*n,h:k(o[da])*n,m:k(o[ca])*n,s:k(o[ha])*n,ms:k(Ie(1e3*o[fa]))*n}):(o=Xa.exec(t))?(n="-"===o[1]?-1:1,r={y:qe(o[2],n),M:qe(o[3],n),w:qe(o[4],n),d:qe(o[5],n),h:qe(o[6],n),m:qe(o[7],n),s:qe(o[8],n)}):null==r?r={}:"object"==typeof r&&("from"in r||"to"in r)&&(a=Xe(_e(r.from),_e(r.to)),r={},r.ms=a.milliseconds,r.M=a.months),i=new Pe(r),Te(t)&&c(t,"_locale")&&(i._locale=t._locale),i}function qe(t,e){var n=t&&parseFloat(t.replace(",","."));return(isNaN(n)?0:n)*e}function Ze(t,e){var n={milliseconds:0,months:0};return n.months=e.month()-t.month()+12*(e.year()-t.year()),t.clone().add(n.months,"M").isAfter(e)&&--n.months,n.milliseconds=+e-+t.clone().add(n.months,"M"),n}function Xe(t,e){var n;return t.isValid()&&e.isValid()?(e=Oe(e,t),t.isBefore(e)?n=Ze(t,e):(n=Ze(e,t),n.milliseconds=-n.milliseconds,n.months=-n.months),n):{milliseconds:0,months:0}}function Je(t,e){return function(n,i){var a,r;return null===i||isNaN(+i)||(D(e,"moment()."+e+"(period, number) is deprecated. Please use moment()."+e+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),r=n,n=i,i=r),n="string"==typeof n?+n:n,a=Ge(n,i),Ke(this,a,t),this}}function Ke(e,n,i,a){var r=n._milliseconds,o=Ie(n._days),s=Ie(n._months);e.isValid()&&(a=null==a||a,r&&e._d.setTime(e._d.valueOf()+r*i),o&&j(e,"Date",H(e,"Date")+o*i),s&&ct(e,H(e,"Month")+s*i),a&&t.updateOffset(e,o||s))}function Qe(t,e){var n=t.diff(e,"days",!0);return n<-6?"sameElse":n<-1?"lastWeek":n<0?"lastDay":n<1?"sameDay":n<2?"nextDay":n<7?"nextWeek":"sameElse"}function $e(e,n){var i=e||_e(),a=Oe(i,this).startOf("day"),r=t.calendarFormat(this,a)||"sameElse",o=n&&(C(n[r])?n[r].call(this,i):n[r]);return this.format(o||this.localeData().calendar(r,this,_e(i)))}function tn(){return new b(this)}function en(t,e){var n=x(t)?t:_e(t);return!(!this.isValid()||!n.isValid())&&(e=Y(s(e)?"millisecond":e),"millisecond"===e?this.valueOf()>n.valueOf():n.valueOf()9999?K(t,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):C(Date.prototype.toISOString)?this.toDate().toISOString():K(t,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function hn(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var t="moment",e="";this.isLocal()||(t=0===this.utcOffset()?"moment.utc":"moment.parseZone",e="Z");var n="["+t+'("]',i=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",a="-MM-DD[T]HH:mm:ss.SSS",r=e+'[")]';return this.format(n+i+a+r)}function fn(e){e||(e=this.isUtc()?t.defaultFormatUtc:t.defaultFormat);var n=K(this,e);return this.localeData().postformat(n)}function gn(t,e){return this.isValid()&&(x(t)&&t.isValid()||_e(t).isValid())?Ge({to:this,from:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()}function pn(t){return this.from(_e(),t)}function mn(t,e){return this.isValid()&&(x(t)&&t.isValid()||_e(t).isValid())?Ge({from:this,to:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()}function vn(t){return this.to(_e(),t)}function yn(t){var e;return void 0===t?this._locale._abbr:(e=ie(t),null!=e&&(this._locale=e),this)}function bn(){return this._locale}function xn(t){switch(t=Y(t)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":case"date":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===t&&this.weekday(0),"isoWeek"===t&&this.isoWeekday(1),"quarter"===t&&this.month(3*Math.floor(this.month()/3)),this}function _n(t){return t=Y(t),void 0===t||"millisecond"===t?this:("date"===t&&(t="day"),this.startOf(t).add(1,"isoWeek"===t?"week":t).subtract(1,"ms"))}function kn(){return this._d.valueOf()-6e4*(this._offset||0)}function wn(){return Math.floor(this.valueOf()/1e3)}function Mn(){return new Date(this.valueOf())}function Sn(){var t=this;return[t.year(),t.month(),t.date(),t.hour(),t.minute(),t.second(),t.millisecond()]}function Dn(){var t=this;return{years:t.year(),months:t.month(),date:t.date(),hours:t.hours(),minutes:t.minutes(),seconds:t.seconds(),milliseconds:t.milliseconds()}}function Cn(){return this.isValid()?this.toISOString():null}function Pn(){return m(this)}function Tn(){return h({},p(this))}function In(){return p(this).overflow}function An(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Fn(t,e){Z(0,[t,t.length],0,e)}function On(t){return Wn.call(this,t,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Rn(t){return Wn.call(this,t,this.isoWeek(),this.isoWeekday(),1,4)}function Ln(){return St(this.year(),1,4)}function Vn(){var t=this.localeData()._week;return St(this.year(),t.dow,t.doy)}function Wn(t,e,n,i,a){var r;return null==t?Mt(this,i,a).year:(r=St(t,i,a),e>r&&(e=r),Yn.call(this,t,e,n,i,a))}function Yn(t,e,n,i,a){var r=wt(t,e,n,i,a),o=_t(r.year,0,r.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}function zn(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)}function Nn(t){var e=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")}function Bn(t,e){e[fa]=k(1e3*("0."+t))}function En(){return this._isUTC?"UTC":""}function Hn(){return this._isUTC?"Coordinated Universal Time":""}function jn(t){return _e(1e3*t)}function Un(){return _e.apply(null,arguments).parseZone()}function Gn(t){return t}function qn(t,e,n,i){var a=ie(),r=f().set(i,e);return a[n](r,t)}function Zn(t,e,n){if(l(t)&&(e=t,t=void 0),t=t||"",null!=e)return qn(t,e,n,"month");var i,a=[];for(i=0;i<12;i++)a[i]=qn(t,i,n,"month");return a}function Xn(t,e,n,i){"boolean"==typeof t?(l(e)&&(n=e,e=void 0),e=e||""):(e=t,n=e,t=!1,l(e)&&(n=e,e=void 0),e=e||"");var a=ie(),r=t?a._week.dow:0;if(null!=n)return qn(e,(n+r)%7,i,"day");var o,s=[];for(o=0;o<7;o++)s[o]=qn(e,(o+r)%7,i,"day");return s}function Jn(t,e){return Zn(t,e,"months")}function Kn(t,e){return Zn(t,e,"monthsShort")}function Qn(t,e,n){return Xn(t,e,n,"weekdays")}function $n(t,e,n){return Xn(t,e,n,"weekdaysShort")}function ti(t,e,n){return Xn(t,e,n,"weekdaysMin")}function ei(){var t=this._data;return this._milliseconds=or(this._milliseconds),this._days=or(this._days),this._months=or(this._months),t.milliseconds=or(t.milliseconds),t.seconds=or(t.seconds),t.minutes=or(t.minutes),t.hours=or(t.hours),t.months=or(t.months),t.years=or(t.years),this}function ni(t,e,n,i){var a=Ge(e,n);return t._milliseconds+=i*a._milliseconds,t._days+=i*a._days,t._months+=i*a._months,t._bubble()}function ii(t,e){return ni(this,t,e,1)}function ai(t,e){return ni(this,t,e,-1)}function ri(t){return t<0?Math.floor(t):Math.ceil(t)}function oi(){var t,e,n,i,a,r=this._milliseconds,o=this._days,s=this._months,l=this._data;return r>=0&&o>=0&&s>=0||r<=0&&o<=0&&s<=0||(r+=864e5*ri(li(s)+o),o=0,s=0),l.milliseconds=r%1e3,t=_(r/1e3),l.seconds=t%60,e=_(t/60),l.minutes=e%60,n=_(e/60),l.hours=n%24,o+=_(n/24),a=_(si(o)),s+=a,o-=ri(li(a)),i=_(s/12),s%=12,l.days=o,l.months=s,l.years=i,this}function si(t){return 4800*t/146097}function li(t){return 146097*t/4800}function ui(t){if(!this.isValid())return NaN;var e,n,i=this._milliseconds;if(t=Y(t),"month"===t||"year"===t)return e=this._days+i/864e5,n=this._months+si(e),"month"===t?n:n/12;switch(e=this._days+Math.round(li(this._months)),t){case"week":return e/7+i/6048e5;case"day":return e+i/864e5;case"hour":return 24*e+i/36e5;case"minute":return 1440*e+i/6e4;case"second":return 86400*e+i/1e3;case"millisecond":return Math.floor(864e5*e)+i;default:throw new Error("Unknown unit "+t)}}function di(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*k(this._months/12):NaN}function ci(t){return function(){return this.as(t)}}function hi(t){return t=Y(t),this.isValid()?this[t+"s"]():NaN}function fi(t){return function(){return this.isValid()?this._data[t]:NaN}}function gi(){return _(this.days()/7)}function pi(t,e,n,i,a){return a.relativeTime(e||1,!!n,t,i)}function mi(t,e,n){var i=Ge(t).abs(),a=kr(i.as("s")),r=kr(i.as("m")),o=kr(i.as("h")),s=kr(i.as("d")),l=kr(i.as("M")),u=kr(i.as("y")),d=a<=wr.ss&&["s",a]||a0,d[4]=n,pi.apply(null,d)}function vi(t){return void 0===t?kr:"function"==typeof t&&(kr=t,!0)}function yi(t,e){return void 0!==wr[t]&&(void 0===e?wr[t]:(wr[t]=e,"s"===t&&(wr.ss=e-1),!0))}function bi(t){if(!this.isValid())return this.localeData().invalidDate();var e=this.localeData(),n=mi(this,!t,e);return t&&(n=e.pastFuture(+this,n)),e.postformat(n)}function xi(){if(!this.isValid())return this.localeData().invalidDate();var t,e,n,i=Mr(this._milliseconds)/1e3,a=Mr(this._days),r=Mr(this._months);t=_(i/60),e=_(t/60),i%=60,t%=60,n=_(r/12),r%=12;var o=n,s=r,l=a,u=e,d=t,c=i,h=this.asSeconds();return h?(h<0?"-":"")+"P"+(o?o+"Y":"")+(s?s+"M":"")+(l?l+"D":"")+(u||d||c?"T":"")+(u?u+"H":"")+(d?d+"M":"")+(c?c+"S":""):"P0D"}var _i,ki;ki=Array.prototype.some?Array.prototype.some:function(t){for(var e=Object(this),n=e.length>>>0,i=0;i68?1900:2e3)};var ka=E("FullYear",!0);Z("w",["ww",2],"wo","week"),Z("W",["WW",2],"Wo","isoWeek"),W("week","w"),W("isoWeek","W"),N("week",5),N("isoWeek",5),$("w",qi),$("ww",qi,Hi),$("W",qi),$("WW",qi,Hi),at(["w","ww","W","WW"],function(t,e,n,i){e[i.substr(0,1)]=k(t)});var wa={dow:0,doy:6};Z("d",0,"do","day"),Z("dd",0,0,function(t){return this.localeData().weekdaysMin(this,t)}),Z("ddd",0,0,function(t){return this.localeData().weekdaysShort(this,t)}),Z("dddd",0,0,function(t){return this.localeData().weekdays(this,t)}),Z("e",0,0,"weekday"),Z("E",0,0,"isoWeekday"),W("day","d"),W("weekday","e"),W("isoWeekday","E"),N("day",11),N("weekday",11),N("isoWeekday",11),$("d",qi),$("e",qi),$("E",qi),$("dd",function(t,e){return e.weekdaysMinRegex(t)}),$("ddd",function(t,e){return e.weekdaysShortRegex(t)}),$("dddd",function(t,e){return e.weekdaysRegex(t)}),at(["dd","ddd","dddd"],function(t,e,n,i){var a=n._locale.weekdaysParse(t,i,n._strict);null!=a?e.d=a:p(n).invalidWeekday=t;
+}),at(["d","e","E"],function(t,e,n,i){e[i]=k(t)});var Ma="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Sa="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Da="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Ca=aa,Pa=aa,Ta=aa;Z("H",["HH",2],0,"hour"),Z("h",["hh",2],0,Ut),Z("k",["kk",2],0,Gt),Z("hmm",0,0,function(){return""+Ut.apply(this)+q(this.minutes(),2)}),Z("hmmss",0,0,function(){return""+Ut.apply(this)+q(this.minutes(),2)+q(this.seconds(),2)}),Z("Hmm",0,0,function(){return""+this.hours()+q(this.minutes(),2)}),Z("Hmmss",0,0,function(){return""+this.hours()+q(this.minutes(),2)+q(this.seconds(),2)}),qt("a",!0),qt("A",!1),W("hour","h"),N("hour",13),$("a",Zt),$("A",Zt),$("H",qi),$("h",qi),$("k",qi),$("HH",qi,Hi),$("hh",qi,Hi),$("kk",qi,Hi),$("hmm",Zi),$("hmmss",Xi),$("Hmm",Zi),$("Hmmss",Xi),it(["H","HH"],da),it(["k","kk"],function(t,e,n){var i=k(t);e[da]=24===i?0:i}),it(["a","A"],function(t,e,n){n._isPm=n._locale.isPM(t),n._meridiem=t}),it(["h","hh"],function(t,e,n){e[da]=k(t),p(n).bigHour=!0}),it("hmm",function(t,e,n){var i=t.length-2;e[da]=k(t.substr(0,i)),e[ca]=k(t.substr(i)),p(n).bigHour=!0}),it("hmmss",function(t,e,n){var i=t.length-4,a=t.length-2;e[da]=k(t.substr(0,i)),e[ca]=k(t.substr(i,2)),e[ha]=k(t.substr(a)),p(n).bigHour=!0}),it("Hmm",function(t,e,n){var i=t.length-2;e[da]=k(t.substr(0,i)),e[ca]=k(t.substr(i))}),it("Hmmss",function(t,e,n){var i=t.length-4,a=t.length-2;e[da]=k(t.substr(0,i)),e[ca]=k(t.substr(i,2)),e[ha]=k(t.substr(a))});var Ia,Aa=/[ap]\.?m?\.?/i,Fa=E("Hours",!0),Oa={calendar:Ii,longDateFormat:Ai,invalidDate:Fi,ordinal:Oi,dayOfMonthOrdinalParse:Ri,relativeTime:Li,months:ya,monthsShort:ba,week:wa,weekdays:Ma,weekdaysMin:Da,weekdaysShort:Sa,meridiemParse:Aa},Ra={},La={},Va=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Wa=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ya=/Z|[+-]\d\d(?::?\d\d)?/,za=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Na=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ba=/^\/?Date\((\-?\d+)/i,Ea=/^((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d?\d\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?:\d\d)?\d\d\s)(\d\d:\d\d)(\:\d\d)?(\s(?:UT|GMT|[ECMP][SD]T|[A-IK-Za-ik-z]|[+-]\d{4}))$/;t.createFromInputFallback=S("value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),t.ISO_8601=function(){},t.RFC_2822=function(){};var Ha=S("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var t=_e.apply(null,arguments);return this.isValid()&&t.isValid()?tthis?this:t:v()}),Ua=function(){return Date.now?Date.now():+new Date},Ga=["year","quarter","month","week","day","hour","minute","second","millisecond"];Ae("Z",":"),Ae("ZZ",""),$("Z",na),$("ZZ",na),it(["Z","ZZ"],function(t,e,n){n._useUTC=!0,n._tzm=Fe(na,t)});var qa=/([\+\-]|\d\d)/gi;t.updateOffset=function(){};var Za=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Xa=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Ge.fn=Pe.prototype,Ge.invalid=Ce;var Ja=Je(1,"add"),Ka=Je(-1,"subtract");t.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",t.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Qa=S("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return void 0===t?this.localeData():this.locale(t)});Z(0,["gg",2],0,function(){return this.weekYear()%100}),Z(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Fn("gggg","weekYear"),Fn("ggggg","weekYear"),Fn("GGGG","isoWeekYear"),Fn("GGGGG","isoWeekYear"),W("weekYear","gg"),W("isoWeekYear","GG"),N("weekYear",1),N("isoWeekYear",1),$("G",ta),$("g",ta),$("GG",qi,Hi),$("gg",qi,Hi),$("GGGG",Ki,Ui),$("gggg",Ki,Ui),$("GGGGG",Qi,Gi),$("ggggg",Qi,Gi),at(["gggg","ggggg","GGGG","GGGGG"],function(t,e,n,i){e[i.substr(0,2)]=k(t)}),at(["gg","GG"],function(e,n,i,a){n[a]=t.parseTwoDigitYear(e)}),Z("Q",0,"Qo","quarter"),W("quarter","Q"),N("quarter",7),$("Q",Ei),it("Q",function(t,e){e[la]=3*(k(t)-1)}),Z("D",["DD",2],"Do","date"),W("date","D"),N("date",9),$("D",qi),$("DD",qi,Hi),$("Do",function(t,e){return t?e._dayOfMonthOrdinalParse||e._ordinalParse:e._dayOfMonthOrdinalParseLenient}),it(["D","DD"],ua),it("Do",function(t,e){e[ua]=k(t.match(qi)[0],10)});var $a=E("Date",!0);Z("DDD",["DDDD",3],"DDDo","dayOfYear"),W("dayOfYear","DDD"),N("dayOfYear",4),$("DDD",Ji),$("DDDD",ji),it(["DDD","DDDD"],function(t,e,n){n._dayOfYear=k(t)}),Z("m",["mm",2],0,"minute"),W("minute","m"),N("minute",14),$("m",qi),$("mm",qi,Hi),it(["m","mm"],ca);var tr=E("Minutes",!1);Z("s",["ss",2],0,"second"),W("second","s"),N("second",15),$("s",qi),$("ss",qi,Hi),it(["s","ss"],ha);var er=E("Seconds",!1);Z("S",0,0,function(){return~~(this.millisecond()/100)}),Z(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),Z(0,["SSS",3],0,"millisecond"),Z(0,["SSSS",4],0,function(){return 10*this.millisecond()}),Z(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),Z(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),Z(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),Z(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),Z(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),W("millisecond","ms"),N("millisecond",16),$("S",Ji,Ei),$("SS",Ji,Hi),$("SSS",Ji,ji);var nr;for(nr="SSSS";nr.length<=9;nr+="S")$(nr,$i);for(nr="S";nr.length<=9;nr+="S")it(nr,Bn);var ir=E("Milliseconds",!1);Z("z",0,0,"zoneAbbr"),Z("zz",0,0,"zoneName");var ar=b.prototype;ar.add=Ja,ar.calendar=$e,ar.clone=tn,ar.diff=ln,ar.endOf=_n,ar.format=fn,ar.from=gn,ar.fromNow=pn,ar.to=mn,ar.toNow=vn,ar.get=U,ar.invalidAt=In,ar.isAfter=en,ar.isBefore=nn,ar.isBetween=an,ar.isSame=rn,ar.isSameOrAfter=on,ar.isSameOrBefore=sn,ar.isValid=Pn,ar.lang=Qa,ar.locale=yn,ar.localeData=bn,ar.max=ja,ar.min=Ha,ar.parsingFlags=Tn,ar.set=G,ar.startOf=xn,ar.subtract=Ka,ar.toArray=Sn,ar.toObject=Dn,ar.toDate=Mn,ar.toISOString=cn,ar.inspect=hn,ar.toJSON=Cn,ar.toString=dn,ar.unix=wn,ar.valueOf=kn,ar.creationData=An,ar.year=ka,ar.isLeapYear=bt,ar.weekYear=On,ar.isoWeekYear=Rn,ar.quarter=ar.quarters=zn,ar.month=ht,ar.daysInMonth=ft,ar.week=ar.weeks=Tt,ar.isoWeek=ar.isoWeeks=It,ar.weeksInYear=Vn,ar.isoWeeksInYear=Ln,ar.date=$a,ar.day=ar.days=Yt,ar.weekday=zt,ar.isoWeekday=Nt,ar.dayOfYear=Nn,ar.hour=ar.hours=Fa,ar.minute=ar.minutes=tr,ar.second=ar.seconds=er,ar.millisecond=ar.milliseconds=ir,ar.utcOffset=Le,ar.utc=We,ar.local=Ye,ar.parseZone=ze,ar.hasAlignedHourOffset=Ne,ar.isDST=Be,ar.isLocal=He,ar.isUtcOffset=je,ar.isUtc=Ue,ar.isUTC=Ue,ar.zoneAbbr=En,ar.zoneName=Hn,ar.dates=S("dates accessor is deprecated. Use date instead.",$a),ar.months=S("months accessor is deprecated. Use month instead",ht),ar.years=S("years accessor is deprecated. Use year instead",ka),ar.zone=S("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Ve),ar.isDSTShifted=S("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ee);var rr=I.prototype;rr.calendar=A,rr.longDateFormat=F,rr.invalidDate=O,rr.ordinal=R,rr.preparse=Gn,rr.postformat=Gn,rr.relativeTime=L,rr.pastFuture=V,rr.set=P,rr.months=st,rr.monthsShort=lt,rr.monthsParse=dt,rr.monthsRegex=pt,rr.monthsShortRegex=gt,rr.week=Dt,rr.firstDayOfYear=Pt,rr.firstDayOfWeek=Ct,rr.weekdays=Ot,rr.weekdaysMin=Lt,rr.weekdaysShort=Rt,rr.weekdaysParse=Wt,rr.weekdaysRegex=Bt,rr.weekdaysShortRegex=Et,rr.weekdaysMinRegex=Ht,rr.isPM=Xt,rr.meridiem=Jt,te("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,n=1===k(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+n}}),t.lang=S("moment.lang is deprecated. Use moment.locale instead.",te),t.langData=S("moment.langData is deprecated. Use moment.localeData instead.",ie);var or=Math.abs,sr=ci("ms"),lr=ci("s"),ur=ci("m"),dr=ci("h"),cr=ci("d"),hr=ci("w"),fr=ci("M"),gr=ci("y"),pr=fi("milliseconds"),mr=fi("seconds"),vr=fi("minutes"),yr=fi("hours"),br=fi("days"),xr=fi("months"),_r=fi("years"),kr=Math.round,wr={ss:44,s:45,m:45,h:22,d:26,M:11},Mr=Math.abs,Sr=Pe.prototype;return Sr.isValid=De,Sr.abs=ei,Sr.add=ii,Sr.subtract=ai,Sr.as=ui,Sr.asMilliseconds=sr,Sr.asSeconds=lr,Sr.asMinutes=ur,Sr.asHours=dr,Sr.asDays=cr,Sr.asWeeks=hr,Sr.asMonths=fr,Sr.asYears=gr,Sr.valueOf=di,Sr._bubble=oi,Sr.get=hi,Sr.milliseconds=pr,Sr.seconds=mr,Sr.minutes=vr,Sr.hours=yr,Sr.days=br,Sr.weeks=gi,Sr.months=xr,Sr.years=_r,Sr.humanize=bi,Sr.toISOString=xi,Sr.toString=xi,Sr.toJSON=xi,Sr.locale=yn,Sr.localeData=bn,Sr.toIsoString=S("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",xi),Sr.lang=Qa,Z("X",0,0,"unix"),Z("x",0,0,"valueOf"),$("x",ta),$("X",ia),it("X",function(t,e,n){n._d=new Date(1e3*parseFloat(t,10))}),it("x",function(t,e,n){n._d=new Date(k(t))}),t.version="2.18.1",i(_e),t.fn=ar,t.min=we,t.max=Me,t.now=Ua,t.utc=f,t.unix=jn,t.months=Jn,t.isDate=u,t.locale=te,t.invalid=v,t.duration=Ge,t.isMoment=x,t.weekdays=Qn,t.parseZone=Un,t.localeData=ie,t.isDuration=Te,t.monthsShort=Kn,t.weekdaysMin=ti,t.defineLocale=ee,t.updateLocale=ne,t.locales=ae,t.weekdaysShort=$n,t.normalizeUnits=Y,t.relativeTimeRounding=vi,t.relativeTimeThreshold=yi,t.calendarFormat=Qe,t.prototype=ar,t})},{}],7:[function(t,e,n){var i=t(28)();t(26)(i),t(40)(i),t(22)(i),t(25)(i),t(30)(i),t(21)(i),t(23)(i),t(24)(i),t(29)(i),t(32)(i),t(33)(i),t(31)(i),t(27)(i),t(34)(i),t(35)(i),t(36)(i),t(37)(i),t(38)(i),t(46)(i),t(44)(i),t(45)(i),t(47)(i),t(48)(i),t(49)(i),t(15)(i),t(16)(i),t(17)(i),t(18)(i),t(19)(i),t(20)(i),t(8)(i),t(9)(i),t(10)(i),t(11)(i),t(12)(i),t(13)(i),t(14)(i);var a=[];a.push(t(41)(i),t(42)(i),t(43)(i)),i.plugins.register(a),e.exports=i,"undefined"!=typeof window&&(window.Chart=i)},{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,40:40,41:41,42:42,43:43,44:44,45:45,46:46,47:47,48:48,49:49,8:8,9:9}],8:[function(t,e,n){"use strict";e.exports=function(t){t.Bar=function(e,n){return n.type="bar",new t(e,n)}}},{}],9:[function(t,e,n){"use strict";e.exports=function(t){t.Bubble=function(e,n){return n.type="bubble",new t(e,n)}}},{}],10:[function(t,e,n){"use strict";e.exports=function(t){t.Doughnut=function(e,n){return n.type="doughnut",new t(e,n)}}},{}],11:[function(t,e,n){"use strict";e.exports=function(t){t.Line=function(e,n){return n.type="line",new t(e,n)}}},{}],12:[function(t,e,n){"use strict";e.exports=function(t){t.PolarArea=function(e,n){return n.type="polarArea",new t(e,n)}}},{}],13:[function(t,e,n){"use strict";e.exports=function(t){t.Radar=function(e,n){return n.type="radar",new t(e,n)}}},{}],14:[function(t,e,n){"use strict";e.exports=function(t){var e={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-1"}],yAxes:[{type:"linear",position:"left",id:"y-axis-1"}]},tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}};t.defaults.scatter=e,t.controllers.scatter=t.controllers.line,t.Scatter=function(e,n){return n.type="scatter",new t(e,n)}}},{}],15:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bar={hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}},t.controllers.bar=t.DatasetController.extend({dataElementType:t.elements.Rectangle,initialize:function(){var e,n=this;t.DatasetController.prototype.initialize.apply(n,arguments),e=n.getMeta(),e.stack=n.getDataset().stack,e.bar=!0},update:function(t){var e,n,i=this,a=i.getMeta().data;for(i._ruler=i.getRuler(),e=0,n=a.length;e=0&&a>0)&&(m+=a));return r=c.getPixelForValue(m),o=c.getPixelForValue(m+f),s=(o-r)/2,{size:s,base:r,head:o,center:o+s/2}},calculateBarIndexPixels:function(t,e,n){var i=this,a=n.scale,r=i.chart.isCombo,o=i.getStackIndex(t),s=a.getPixelForValue(null,e,t,r),l=n.barSize;return s-=r?n.tickSize/2:0,s+=n.fullBarSize*o,s+=n.categorySpacing/2,s+=n.barSpacing/2,{size:l,base:s,head:s+l,center:s+l/2}},draw:function(){var t,n=this,i=n.chart,a=n.getMeta().data,r=n.getDataset(),o=a.length,s=0;for(e.canvas.clipArea(i.ctx,i.chartArea);s0&&(t[0].yLabel?n=t[0].yLabel:e.labels.length>0&&t[0].index');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var r=0;r '),a[r]&&e.push(a[r]),e.push("");return e.push(""),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var r=t.getDatasetMeta(0),o=n.datasets[0],s=r.data[a],l=s&&s.custom||{},u=e.getValueAtIndexOrDefault,d=t.options.elements.arc,c=l.backgroundColor?l.backgroundColor:u(o.backgroundColor,a,d.backgroundColor),h=l.borderColor?l.borderColor:u(o.borderColor,a,d.borderColor),f=l.borderWidth?l.borderWidth:u(o.borderWidth,a,d.borderWidth);return{text:i,fillStyle:c,strokeStyle:h,lineWidth:f,hidden:isNaN(o.data[a])||r.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,r=e.index,o=this.chart;for(n=0,i=(o.data.datasets||[]).length;n=Math.PI?-1:g<-Math.PI?1:0);var p=g+f,m={x:Math.cos(g),y:Math.sin(g)},v={x:Math.cos(p),y:Math.sin(p)},y=g<=0&&0<=p||g<=2*Math.PI&&2*Math.PI<=p,b=g<=.5*Math.PI&&.5*Math.PI<=p||g<=2.5*Math.PI&&2.5*Math.PI<=p,x=g<=-Math.PI&&-Math.PI<=p||g<=Math.PI&&Math.PI<=p,_=g<=.5*-Math.PI&&.5*-Math.PI<=p||g<=1.5*Math.PI&&1.5*Math.PI<=p,k=h/100,w={x:x?-1:Math.min(m.x*(m.x<0?1:k),v.x*(v.x<0?1:k)),y:_?-1:Math.min(m.y*(m.y<0?1:k),v.y*(v.y<0?1:k))},M={x:y?1:Math.max(m.x*(m.x>0?1:k),v.x*(v.x>0?1:k)),y:b?1:Math.max(m.y*(m.y>0?1:k),v.y*(v.y>0?1:k))},S={width:.5*(M.x-w.x),height:.5*(M.y-w.y)};u=Math.min(s/S.width,l/S.height),d={x:(M.x+w.x)*-.5,y:(M.y+w.y)*-.5}}i.borderWidth=n.getMaxBorderWidth(c.data),i.outerRadius=Math.max((u-i.borderWidth)/2,0),i.innerRadius=Math.max(h?i.outerRadius/100*h:0,0),i.radiusLength=(i.outerRadius-i.innerRadius)/i.getVisibleDatasetCount(),i.offsetX=d.x*i.outerRadius,i.offsetY=d.y*i.outerRadius,c.total=n.calculateTotal(),n.outerRadius=i.outerRadius-i.radiusLength*n.getRingIndex(n.index),n.innerRadius=Math.max(n.outerRadius-i.radiusLength,0),e.each(c.data,function(e,i){n.updateElement(e,i,t)})},updateElement:function(t,n,i){var a=this,r=a.chart,o=r.chartArea,s=r.options,l=s.animation,u=(o.left+o.right)/2,d=(o.top+o.bottom)/2,c=s.rotation,h=s.rotation,f=a.getDataset(),g=i&&l.animateRotate?0:t.hidden?0:a.calculateCircumference(f.data[n])*(s.circumference/(2*Math.PI)),p=i&&l.animateScale?0:a.innerRadius,m=i&&l.animateScale?0:a.outerRadius,v=e.getValueAtIndexOrDefault;e.extend(t,{_datasetIndex:a.index,_index:n,_model:{x:u+r.offsetX,y:d+r.offsetY,startAngle:c,endAngle:h,circumference:g,outerRadius:m,innerRadius:p,label:v(f.label,n,r.data.labels[n])}});var y=t._model;this.removeHoverStyle(t),i&&l.animateRotate||(0===n?y.startAngle=s.rotation:y.startAngle=a.getMeta().data[n-1]._model.endAngle,y.endAngle=y.startAngle+y.circumference),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},calculateTotal:function(){var t,n=this.getDataset(),i=this.getMeta(),a=0;return e.each(i.data,function(e,i){t=n.data[i],isNaN(t)||e.hidden||(a+=Math.abs(t))}),a},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(t/e):0},getMaxBorderWidth:function(t){for(var e,n,i=0,a=this.index,r=t.length,o=0;oi?e:i,i=n>i?n:i;return i}})}},{}],18:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return n.getValueOrDefault(t.showLine,e.showLines)}var n=t.helpers;t.defaults.line={showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}},t.controllers.line=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,update:function(t){var i,a,r,o=this,s=o.getMeta(),l=s.dataset,u=s.data||[],d=o.chart.options,c=d.elements.line,h=o.getScaleForId(s.yAxisID),f=o.getDataset(),g=e(f,d);for(g&&(r=l.custom||{},void 0!==f.tension&&void 0===f.lineTension&&(f.lineTension=f.tension),l._scale=h,l._datasetIndex=o.index,l._children=u,l._model={spanGaps:f.spanGaps?f.spanGaps:d.spanGaps,tension:r.tension?r.tension:n.getValueOrDefault(f.lineTension,c.tension),backgroundColor:r.backgroundColor?r.backgroundColor:f.backgroundColor||c.backgroundColor,borderWidth:r.borderWidth?r.borderWidth:f.borderWidth||c.borderWidth,borderColor:r.borderColor?r.borderColor:f.borderColor||c.borderColor,borderCapStyle:r.borderCapStyle?r.borderCapStyle:f.borderCapStyle||c.borderCapStyle,borderDash:r.borderDash?r.borderDash:f.borderDash||c.borderDash,borderDashOffset:r.borderDashOffset?r.borderDashOffset:f.borderDashOffset||c.borderDashOffset,borderJoinStyle:r.borderJoinStyle?r.borderJoinStyle:f.borderJoinStyle||c.borderJoinStyle,fill:r.fill?r.fill:void 0!==f.fill?f.fill:c.fill,steppedLine:r.steppedLine?r.steppedLine:n.getValueOrDefault(f.steppedLine,c.stepped),cubicInterpolationMode:r.cubicInterpolationMode?r.cubicInterpolationMode:n.getValueOrDefault(f.cubicInterpolationMode,c.cubicInterpolationMode)},l.pivot()),i=0,a=u.length;i');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var r=0;r '),a[r]&&e.push(a[r]),e.push("");return e.push(""),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var r=t.getDatasetMeta(0),o=n.datasets[0],s=r.data[a],l=s.custom||{},u=e.getValueAtIndexOrDefault,d=t.options.elements.arc,c=l.backgroundColor?l.backgroundColor:u(o.backgroundColor,a,d.backgroundColor),h=l.borderColor?l.borderColor:u(o.borderColor,a,d.borderColor),f=l.borderWidth?l.borderWidth:u(o.borderWidth,a,d.borderWidth);return{text:i,fillStyle:c,strokeStyle:h,lineWidth:f,hidden:isNaN(o.data[a])||r.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,r=e.index,o=this.chart;for(n=0,i=(o.data.datasets||[]).length;n0&&!isNaN(t)?2*Math.PI/e:0}})}},{}],20:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.radar={aspectRatio:1,scale:{type:"radialLinear"},elements:{line:{tension:0}}},t.controllers.radar=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,linkScales:e.noop,update:function(t){var n=this,i=n.getMeta(),a=i.dataset,r=i.data,o=a.custom||{},s=n.getDataset(),l=n.chart.options.elements.line,u=n.chart.scale;void 0!==s.tension&&void 0===s.lineTension&&(s.lineTension=s.tension),e.extend(i.dataset,{_datasetIndex:n.index,_scale:u,_children:r,_loop:!0,_model:{tension:o.tension?o.tension:e.getValueOrDefault(s.lineTension,l.tension),backgroundColor:o.backgroundColor?o.backgroundColor:s.backgroundColor||l.backgroundColor,borderWidth:o.borderWidth?o.borderWidth:s.borderWidth||l.borderWidth,borderColor:o.borderColor?o.borderColor:s.borderColor||l.borderColor,fill:o.fill?o.fill:void 0!==s.fill?s.fill:l.fill,borderCapStyle:o.borderCapStyle?o.borderCapStyle:s.borderCapStyle||l.borderCapStyle,borderDash:o.borderDash?o.borderDash:s.borderDash||l.borderDash,borderDashOffset:o.borderDashOffset?o.borderDashOffset:s.borderDashOffset||l.borderDashOffset,borderJoinStyle:o.borderJoinStyle?o.borderJoinStyle:s.borderJoinStyle||l.borderJoinStyle}}),i.dataset.pivot(),e.each(r,function(e,i){n.updateElement(e,i,t)},n),n.updateBezierControlPoints()},updateElement:function(t,n,i){var a=this,r=t.custom||{},o=a.getDataset(),s=a.chart.scale,l=a.chart.options.elements.point,u=s.getPointPositionForValue(n,o.data[n]);void 0!==o.radius&&void 0===o.pointRadius&&(o.pointRadius=o.radius),void 0!==o.hitRadius&&void 0===o.pointHitRadius&&(o.pointHitRadius=o.hitRadius),e.extend(t,{_datasetIndex:a.index,_index:n,_scale:s,_model:{x:i?s.xCenter:u.x,y:i?s.yCenter:u.y,tension:r.tension?r.tension:e.getValueOrDefault(o.lineTension,a.chart.options.elements.line.tension),radius:r.radius?r.radius:e.getValueAtIndexOrDefault(o.pointRadius,n,l.radius),backgroundColor:r.backgroundColor?r.backgroundColor:e.getValueAtIndexOrDefault(o.pointBackgroundColor,n,l.backgroundColor),borderColor:r.borderColor?r.borderColor:e.getValueAtIndexOrDefault(o.pointBorderColor,n,l.borderColor),borderWidth:r.borderWidth?r.borderWidth:e.getValueAtIndexOrDefault(o.pointBorderWidth,n,l.borderWidth),pointStyle:r.pointStyle?r.pointStyle:e.getValueAtIndexOrDefault(o.pointStyle,n,l.pointStyle),hitRadius:r.hitRadius?r.hitRadius:e.getValueAtIndexOrDefault(o.pointHitRadius,n,l.hitRadius)}}),t._model.skip=r.skip?r.skip:isNaN(t._model.x)||isNaN(t._model.y)},updateBezierControlPoints:function(){var t=this.chart.chartArea,n=this.getMeta();e.each(n.data,function(i,a){var r=i._model,o=e.splineCurve(e.previousItem(n.data,a,!0)._model,r,e.nextItem(n.data,a,!0)._model,r.tension);r.controlPointPreviousX=Math.max(Math.min(o.previous.x,t.right),t.left),r.controlPointPreviousY=Math.max(Math.min(o.previous.y,t.bottom),t.top),r.controlPointNextX=Math.max(Math.min(o.next.x,t.right),t.left),r.controlPointNextY=Math.max(Math.min(o.next.y,t.bottom),t.top),i.pivot()})},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,r=t._model;r.radius=i.hoverRadius?i.hoverRadius:e.getValueAtIndexOrDefault(n.pointHoverRadius,a,this.chart.options.elements.point.hoverRadius),r.backgroundColor=i.hoverBackgroundColor?i.hoverBackgroundColor:e.getValueAtIndexOrDefault(n.pointHoverBackgroundColor,a,e.getHoverColor(r.backgroundColor)),r.borderColor=i.hoverBorderColor?i.hoverBorderColor:e.getValueAtIndexOrDefault(n.pointHoverBorderColor,a,e.getHoverColor(r.borderColor)),r.borderWidth=i.hoverBorderWidth?i.hoverBorderWidth:e.getValueAtIndexOrDefault(n.pointHoverBorderWidth,a,r.borderWidth)},removeHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,r=t._model,o=this.chart.options.elements.point;r.radius=i.radius?i.radius:e.getValueAtIndexOrDefault(n.pointRadius,a,o.radius),r.backgroundColor=i.backgroundColor?i.backgroundColor:e.getValueAtIndexOrDefault(n.pointBackgroundColor,a,o.backgroundColor),r.borderColor=i.borderColor?i.borderColor:e.getValueAtIndexOrDefault(n.pointBorderColor,a,o.borderColor),r.borderWidth=i.borderWidth?i.borderWidth:e.getValueAtIndexOrDefault(n.pointBorderWidth,a,o.borderWidth)}})}},{}],21:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.animation={duration:1e3,easing:"easeOutQuart",onProgress:e.noop,onComplete:e.noop},t.Animation=t.Element.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),t.animationService={frameDuration:17,animations:[],dropFrames:0,request:null,addAnimation:function(t,e,n,i){var a,r,o=this.animations;for(e.chart=t,i||(t.animating=!0),a=0,r=o.length;a1&&(n=Math.floor(t.dropFrames),t.dropFrames=t.dropFrames%1),t.advance(1+n);var i=Date.now();t.dropFrames+=(i-e)/t.frameDuration,t.animations.length>0&&t.requestAnimationFrame()},advance:function(t){for(var n,i,a=this.animations,r=0;r=n.numSteps?(e.callback(n.onAnimationComplete,[n],i),i.animating=!1,a.splice(r,1)):++r}},Object.defineProperty(t.Animation.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(t.Animation.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}})}},{}],22:[function(t,e,n){"use strict";e.exports=function(t){var e=t.canvasHelpers={};e.drawPoint=function(e,n,i,a,r){var o,s,l,u,d,c;if("object"==typeof n&&(o=n.toString(),"[object HTMLImageElement]"===o||"[object HTMLCanvasElement]"===o))return void e.drawImage(n,a-n.width/2,r-n.height/2,n.width,n.height);if(!(isNaN(i)||i<=0)){switch(n){default:e.beginPath(),e.arc(a,r,i,0,2*Math.PI),e.closePath(),e.fill();break;case"triangle":e.beginPath(),s=3*i/Math.sqrt(3),d=s*Math.sqrt(3)/2,e.moveTo(a-s/2,r+d/3),e.lineTo(a+s/2,r+d/3),e.lineTo(a,r-2*d/3),e.closePath(),e.fill();break;case"rect":c=1/Math.SQRT2*i,e.beginPath(),e.fillRect(a-c,r-c,2*c,2*c),e.strokeRect(a-c,r-c,2*c,2*c);break;case"rectRounded":var h=i/Math.SQRT2,f=a-h,g=r-h,p=Math.SQRT2*i;t.helpers.drawRoundedRectangle(e,f,g,p,p,i/2),e.fill();break;case"rectRot":c=1/Math.SQRT2*i,e.beginPath(),e.moveTo(a-c,r),e.lineTo(a,r+c),e.lineTo(a+c,r),e.lineTo(a,r-c),e.closePath(),e.fill();break;case"cross":e.beginPath(),e.moveTo(a,r+i),e.lineTo(a,r-i),e.moveTo(a-i,r),e.lineTo(a+i,r),e.closePath();break;case"crossRot":e.beginPath(),l=Math.cos(Math.PI/4)*i,u=Math.sin(Math.PI/4)*i,e.moveTo(a-l,r-u),e.lineTo(a+l,r+u),e.moveTo(a-l,r+u),e.lineTo(a+l,r-u),e.closePath();break;case"star":e.beginPath(),e.moveTo(a,r+i),e.lineTo(a,r-i),e.moveTo(a-i,r),e.lineTo(a+i,r),l=Math.cos(Math.PI/4)*i,u=Math.sin(Math.PI/4)*i,e.moveTo(a-l,r-u),e.lineTo(a+l,r+u),e.moveTo(a-l,r+u),e.lineTo(a+l,r-u),e.closePath();break;case"line":e.beginPath(),e.moveTo(a-i,r),e.lineTo(a+i,r),e.closePath();break;case"dash":e.beginPath(),e.moveTo(a,r),e.lineTo(a+i,r),e.closePath()}e.stroke()}},e.clipArea=function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},e.unclipArea=function(t){t.restore()},e.lineTo=function(t,e,n,i){return n.steppedLine?("after"===n.steppedLine?t.lineTo(e.x,n.y):t.lineTo(n.x,e.y),void t.lineTo(n.x,n.y)):n.tension?void t.bezierCurveTo(i?e.controlPointPreviousX:e.controlPointNextX,i?e.controlPointPreviousY:e.controlPointNextY,i?n.controlPointNextX:n.controlPointPreviousX,i?n.controlPointNextY:n.controlPointPreviousY,n.x,n.y):void t.lineTo(n.x,n.y)},t.helpers.canvas=e}},{}],23:[function(t,e,n){"use strict";e.exports=function(t){function e(e){e=e||{};var n=e.data=e.data||{};return n.datasets=n.datasets||[],n.labels=n.labels||[],e.options=a.configMerge(t.defaults.global,t.defaults[e.type],e.options||{}),e}function n(t){var e=t.options;e.scale?t.scale.options=e.scale:e.scales&&e.scales.xAxes.concat(e.scales.yAxes).forEach(function(e){t.scales[e.id].options=e}),t.tooltip._options=e.tooltips}function i(t){return"top"===t||"bottom"===t}var a=t.helpers,r=t.plugins,o=t.platform;t.types={},t.instances={},t.controllers={},a.extend(t.prototype,{construct:function(n,i){var r=this;i=e(i);var s=o.acquireContext(n,i),l=s&&s.canvas,u=l&&l.height,d=l&&l.width;return r.id=a.uid(),r.ctx=s,r.canvas=l,r.config=i,r.width=d,r.height=u,r.aspectRatio=u?d/u:null,r.options=i.options,r._bufferedRender=!1,r.chart=r,r.controller=r,t.instances[r.id]=r,Object.defineProperty(r,"data",{get:function(){return r.config.data},set:function(t){r.config.data=t}}),s&&l?(r.initialize(),void r.update()):void console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return r.notify(t,"beforeInit"),a.retinaScale(t),t.bindEvents(),t.options.responsive&&t.resize(!0),t.ensureScalesHaveIDs(),t.buildScales(),t.initToolTip(),r.notify(t,"afterInit"),t},clear:function(){return a.clear(this),this},stop:function(){return t.animationService.cancelAnimation(this),this},resize:function(t){var e=this,n=e.options,i=e.canvas,o=n.maintainAspectRatio&&e.aspectRatio||null,s=Math.floor(a.getMaximumWidth(i)),l=Math.floor(o?s/o:a.getMaximumHeight(i));if((e.width!==s||e.height!==l)&&(i.width=e.width=s,i.height=e.height=l,i.style.width=s+"px",i.style.height=l+"px",a.retinaScale(e),!t)){var u={width:s,height:l};r.notify(e,"resize",[u]),e.options.onResize&&e.options.onResize(e,u),e.stop(),e.update(e.options.responsiveAnimationDuration)}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},n=t.scale;a.each(e.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),a.each(e.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),n&&(n.id=n.id||"scale")},buildScales:function(){var e=this,n=e.options,r=e.scales={},o=[];n.scales&&(o=o.concat((n.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category",dposition:"bottom"}}),(n.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear",dposition:"left"}}))),n.scale&&o.push({options:n.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),a.each(o,function(n){var o=n.options,s=a.getValueOrDefault(o.type,n.dtype),l=t.scaleService.getScaleConstructor(s);if(l){i(o.position)!==i(n.dposition)&&(o.position=n.dposition);var u=new l({id:o.id,options:o,ctx:e.ctx,chart:e});r[u.id]=u,n.isDefault&&(e.scale=u)}}),t.scaleService.addScalesToLayout(this)},buildOrUpdateControllers:function(){var e=this,n=[],i=[];if(a.each(e.data.datasets,function(a,r){var o=e.getDatasetMeta(r);if(o.type||(o.type=a.type||e.config.type),n.push(o.type),o.controller)o.controller.updateIndex(r);else{var s=t.controllers[o.type];if(void 0===s)throw new Error('"'+o.type+'" is not a chart type.');o.controller=new s(e,r),i.push(o.controller)}},e),n.length>1)for(var r=1;r=0;--n)e.isDatasetVisible(n)&&e.drawDataset(n,t);r.notify(e,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var n=this,i=n.getDatasetMeta(t),a={meta:i,index:t,easingValue:e};r.notify(n,"beforeDatasetDraw",[a])!==!1&&(i.controller.draw(e),r.notify(n,"afterDatasetDraw",[a]))},getElementAtEvent:function(e){return t.Interaction.modes.single(this,e)},getElementsAtEvent:function(e){return t.Interaction.modes.label(this,e,{intersect:!0})},getElementsAtXAxis:function(e){return t.Interaction.modes["x-axis"](this,e,{intersect:!0})},getElementsAtEventForMode:function(e,n,i){var a=t.Interaction.modes[n];return"function"==typeof a?a(this,e,i):[]},getDatasetAtEvent:function(e){return t.Interaction.modes.dataset(this,e,{intersect:!0})},getDatasetMeta:function(t){var e=this,n=e.data.datasets[t];n._meta||(n._meta={});var i=n._meta[e.id];return i||(i=n._meta[e.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,n=this.data.datasets.length;e0||(a.forEach(function(e){delete t[e]}),delete t._chartjs)}}var i=t.helpers,a=["push","pop","shift","splice","unshift"];t.DatasetController=function(t,e){this.initialize(t,e)},i.extend(t.DatasetController.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){var n=this;n.chart=t,n.index=e,n.linkScales(),n.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),n=t.getDataset();null===e.xAxisID&&(e.xAxisID=n.xAxisID||t.chart.options.scales.xAxes[0].id),null===e.yAxisID&&(e.yAxisID=n.yAxisID||t.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(t){return this.chart.scales[t]},reset:function(){this.update(!0)},destroy:function(){this._data&&n(this._data,this)},createMetaDataset:function(){var t=this,e=t.datasetElementType;return e&&new e({_chart:t.chart,_datasetIndex:t.index})},createMetaData:function(t){var e=this,n=e.dataElementType;return n&&new n({_chart:e.chart,_datasetIndex:e.index,_index:t})},addElements:function(){var t,e,n=this,i=n.getMeta(),a=n.getDataset().data||[],r=i.data;for(t=0,e=a.length;ti&&t.insertElements(i,a-i)},insertElements:function(t,e){for(var n=0;n=0;a--)e.call(n,t[a],a);else for(a=0;a=i[n].length||!i[n][a].type?i[n].push(r.configMerge(s,e)):e.type&&e.type!==i[n][a].type?i[n][a]=r.configMerge(i[n][a],s,e):i[n][a]=r.configMerge(i[n][a],e)}):(i[n]=[],r.each(e,function(e){var a=r.getValueOrDefault(e.type,"xAxes"===n?"category":"linear");i[n].push(r.configMerge(t.scaleService.getScaleDefaults(a),e))})):i.hasOwnProperty(n)&&"object"==typeof i[n]&&null!==i[n]&&"object"==typeof e?i[n]=r.configMerge(i[n],e):i[n]=e}),i},r.getValueAtIndexOrDefault=function(t,e,n){return void 0===t||null===t?n:r.isArray(t)?e=0;i--){var a=t[i];if(e(a))return a}},r.inherits=function(t){var e=this,n=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},i=function(){this.constructor=n};return i.prototype=e.prototype,n.prototype=new i,n.extend=r.inherits,t&&r.extend(n.prototype,t),n.__super__=e.prototype,n},r.noop=function(){},r.uid=function(){var t=0;return function(){return t++}}(),r.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},r.almostEquals=function(t,e,n){return Math.abs(t-e)t},r.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},r.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},r.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return t=+t,0===t||isNaN(t)?t:t>0?1:-1},r.log10=Math.log10?function(t){return Math.log10(t)}:function(t){return Math.log(t)/Math.LN10},r.toRadians=function(t){return t*(Math.PI/180)},r.toDegrees=function(t){return t*(180/Math.PI)},r.getAngleFromPoint=function(t,e){var n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),r=Math.atan2(i,n);return r<-.5*Math.PI&&(r+=2*Math.PI),{angle:r,distance:a}},r.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},r.aliasPixel=function(t){return t%2===0?0:.5},r.splineCurve=function(t,e,n,i){var a=t.skip?e:t,r=e,o=n.skip?e:n,s=Math.sqrt(Math.pow(r.x-a.x,2)+Math.pow(r.y-a.y,2)),l=Math.sqrt(Math.pow(o.x-r.x,2)+Math.pow(o.y-r.y,2)),u=s/(s+l),d=l/(s+l);u=isNaN(u)?0:u,d=isNaN(d)?0:d;var c=i*u,h=i*d;return{previous:{x:r.x-c*(o.x-a.x),y:r.y-c*(o.y-a.y)},next:{x:r.x+h*(o.x-a.x),y:r.y+h*(o.y-a.y)}}},r.EPSILON=Number.EPSILON||1e-14,r.splineCurveMonotone=function(t){var e,n,i,a,o=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),s=o.length;for(e=0;e0?o[e-1]:null,a=e0?o[e-1]:null,a=e=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},r.previousItem=function(t,e,n){return n?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},r.niceNum=function(t,e){var n,i=Math.floor(r.log10(t)),a=t/Math.pow(10,i);return n=e?a<1.5?1:a<3?2:a<7?5:10:a<=1?1:a<=2?2:a<=5?5:10,n*Math.pow(10,i)};var o=r.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===(t/=1)?1:(n||(n=.3),i0?(n=l[0].clientX,i=l[0].clientY):(n=a.clientX,i=a.clientY);var u=parseFloat(r.getStyle(o,"padding-left")),d=parseFloat(r.getStyle(o,"padding-top")),c=parseFloat(r.getStyle(o,"padding-right")),h=parseFloat(r.getStyle(o,"padding-bottom")),f=s.right-s.left-u-c,g=s.bottom-s.top-d-h;return n=Math.round((n-s.left-u)/f*o.width/e.currentDevicePixelRatio),i=Math.round((i-s.top-d)/g*o.height/e.currentDevicePixelRatio),{x:n,y:i}},r.addEvent=function(t,e,n){t.addEventListener?t.addEventListener(e,n):t.attachEvent?t.attachEvent("on"+e,n):t["on"+e]=n},r.removeEvent=function(t,e,n){t.removeEventListener?t.removeEventListener(e,n,!1):t.detachEvent?t.detachEvent("on"+e,n):t["on"+e]=r.noop},r.getConstraintWidth=function(t){return a(t,"max-width","clientWidth")},r.getConstraintHeight=function(t){return a(t,"max-height","clientHeight")},r.getMaximumWidth=function(t){var e=t.parentNode,n=parseInt(r.getStyle(e,"padding-left"),10),i=parseInt(r.getStyle(e,"padding-right"),10),a=e.clientWidth-n-i,o=r.getConstraintWidth(t);return isNaN(o)?a:Math.min(a,o)},r.getMaximumHeight=function(t){var e=t.parentNode,n=parseInt(r.getStyle(e,"padding-top"),10),i=parseInt(r.getStyle(e,"padding-bottom"),10),a=e.clientHeight-n-i,o=r.getConstraintHeight(t);return isNaN(o)?a:Math.min(a,o)},r.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},r.retinaScale=function(t){var e=t.currentDevicePixelRatio=window.devicePixelRatio||1;if(1!==e){var n=t.canvas,i=t.height,a=t.width;n.height=i*e,n.width=a*e,t.ctx.scale(e,e),n.style.height=i+"px",n.style.width=a+"px"}},r.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},r.fontString=function(t,e,n){return e+" "+t+"px "+n},r.longestText=function(t,e,n,i){i=i||{};var a=i.data=i.data||{},o=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(a=i.data={},o=i.garbageCollect=[],i.font=e),t.font=e;var s=0;r.each(n,function(e){void 0!==e&&null!==e&&r.isArray(e)!==!0?s=r.measureText(t,a,o,s,e):r.isArray(e)&&r.each(e,function(e){void 0===e||null===e||r.isArray(e)||(s=r.measureText(t,a,o,s,e))})});var l=o.length/2;if(l>n.length){for(var u=0;ui&&(i=r),i},r.numberOfLabelLines=function(t){var e=1;return r.each(t,function(t){r.isArray(t)&&t.length>e&&(e=t.length)}),e},r.drawRoundedRectangle=function(t,e,n,i,a,r){t.beginPath(),t.moveTo(e+r,n),t.lineTo(e+i-r,n),t.quadraticCurveTo(e+i,n,e+i,n+r),t.lineTo(e+i,n+a-r),t.quadraticCurveTo(e+i,n+a,e+i-r,n+a),t.lineTo(e+r,n+a),t.quadraticCurveTo(e,n+a,e,n+a-r),t.lineTo(e,n+r),t.quadraticCurveTo(e,n,e+r,n),t.closePath()},r.color=i?function(e){return e instanceof CanvasGradient&&(e=t.defaults.global.defaultColor),i(e)}:function(t){return console.error("Color.js not found!"),t},r.isArray=Array.isArray?function(t){return Array.isArray(t)}:function(t){return"[object Array]"===Object.prototype.toString.call(t)},r.arrayEquals=function(t,e){var n,i,a,o;if(!t||!e||t.length!==e.length)return!1;for(n=0,i=t.length;n0&&(s=t.getDatasetMeta(s[0]._datasetIndex).data),s},"x-axis":function(t,e){return r(t,e,!0)},point:function(t,n){var a=e(n,t);return i(t,a)},nearest:function(t,n,i){var r=e(n,t),o=a(t,r,i.intersect);return o.length>1&&o.sort(function(t,e){var n=t.getArea(),i=e.getArea(),a=n-i;return 0===a&&(a=t._datasetIndex-e._datasetIndex),a}),o.slice(0,1)},x:function(t,i,a){var r=e(i,t),o=[],s=!1;return n(t,function(t){t.inXRange(r.x)&&o.push(t),t.inRange(r.x,r.y)&&(s=!0)}),a.intersect&&!s&&(o=[]),o},y:function(t,i,a){var r=e(i,t),o=[],s=!1;return n(t,function(t){t.inYRange(r.y)&&o.push(t),t.inRange(r.x,r.y)&&(s=!0)}),a.intersect&&!s&&(o=[]),o}}}}},{}],28:[function(t,e,n){"use strict";e.exports=function(){var t=function(t,e){return this.construct(t,e),this};return t.defaults={global:{responsive:!0,responsiveAnimationDuration:0,maintainAspectRatio:!0,events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",showLines:!0,elements:{},legendCallback:function(t){var e=[];e.push('');for(var n=0;n '),t.data.datasets[n].label&&e.push(t.data.datasets[n].label),e.push("");return e.push(" "),e.join("")}}},t.Chart=t,t}},{}],29:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return i.where(t,function(t){return t.position===e})}function n(t,e){t.forEach(function(t,e){return t._tmpIndex_=e,t}),t.sort(function(t,n){var i=e?n:t,a=e?t:n;return i.weight===a.weight?i._tmpIndex_-a._tmpIndex_:i.weight-a.weight}),t.forEach(function(t){delete t._tmpIndex_})}var i=t.helpers;t.layoutService={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,t.boxes.push(e)},removeBox:function(t,e){var n=t.boxes?t.boxes.indexOf(e):-1;n!==-1&&t.boxes.splice(n,1)},configure:function(t,e,n){for(var i,a=["fullWidth","position","weight"],r=a.length,o=0;oc&&ot.maxHeight){o--;break}o++,d=s*u}t.labelRotation=o},afterCalculateTickRotation:function(){i.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){i.callback(this.options.beforeFit,[this])},fit:function(){var t=this,a=t.minSize={width:0,height:0},r=t.options,o=r.ticks,s=r.scaleLabel,l=r.gridLines,u=r.display,d=t.isHorizontal(),c=n(o),h=1.5*n(s).size,f=r.gridLines.tickMarkLength;if(d?a.width=t.isFullWidth()?t.maxWidth-t.margins.left-t.margins.right:t.maxWidth:a.width=u&&l.drawTicks?f:0,d?a.height=u&&l.drawTicks?f:0:a.height=t.maxHeight,s.display&&u&&(d?a.height+=h:a.width+=h),o.display&&u){var g=i.longestText(t.ctx,c.font,t.ticks,t.longestTextCache),p=i.numberOfLabelLines(t.ticks),m=.5*c.size;if(d){t.longestLabelWidth=g;var v=i.toRadians(t.labelRotation),y=Math.cos(v),b=Math.sin(v),x=b*g+c.size*p+m*p;a.height=Math.min(t.maxHeight,a.height+x),t.ctx.font=c.font;var _=t.ticks[0],k=e(t.ctx,_,c.font),w=t.ticks[t.ticks.length-1],M=e(t.ctx,w,c.font);0!==t.labelRotation?(t.paddingLeft="bottom"===r.position?y*k+3:y*m+3,t.paddingRight="bottom"===r.position?y*m+3:y*M+3):(t.paddingLeft=k/2+3,t.paddingRight=M/2+3)}else o.mirror?g=0:g+=t.options.ticks.padding,a.width=Math.min(t.maxWidth,a.width+g),t.paddingTop=c.size/2,t.paddingBottom=c.size/2}t.handleMargins(),t.width=a.width,t.height=a.height},handleMargins:function(){var t=this;t.margins&&(t.paddingLeft=Math.max(t.paddingLeft-t.margins.left,0),t.paddingTop=Math.max(t.paddingTop-t.margins.top,0),t.paddingRight=Math.max(t.paddingRight-t.margins.right,0),t.paddingBottom=Math.max(t.paddingBottom-t.margins.bottom,0))},afterFit:function(){i.callback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){return null===t||"undefined"==typeof t?NaN:"number"!=typeof t||isFinite(t)?"object"==typeof t?t instanceof Date||t.isValid?t:this.getRightValue(this.isHorizontal()?t.x:t.y):t:NaN},getLabelForIndex:i.noop,getPixelForValue:i.noop,getValueForPixel:i.noop,getPixelForTick:function(t,e){var n=this;if(n.isHorizontal()){var i=n.width-(n.paddingLeft+n.paddingRight),a=i/Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),r=a*t+n.paddingLeft;e&&(r+=a/2);var o=n.left+Math.round(r);return o+=n.isFullWidth()?n.margins.left:0}var s=n.height-(n.paddingTop+n.paddingBottom);return n.top+t*(s/(n.ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var n=e.width-(e.paddingLeft+e.paddingRight),i=n*t+e.paddingLeft,a=e.left+Math.round(i);return a+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this,e=t.min,n=t.max;return t.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0},draw:function(e){var a=this,r=a.options;if(r.display){var o,s,l=a.ctx,u=t.defaults.global,d=r.ticks,c=r.gridLines,h=r.scaleLabel,f=0!==a.labelRotation,g=d.autoSkip,p=a.isHorizontal();d.maxTicksLimit&&(s=d.maxTicksLimit);var m=i.getValueOrDefault(d.fontColor,u.defaultFontColor),v=n(d),y=c.drawTicks?c.tickMarkLength:0,b=i.getValueOrDefault(h.fontColor,u.defaultFontColor),x=n(h),_=i.toRadians(a.labelRotation),k=Math.cos(_),w=a.longestLabelWidth*k;l.fillStyle=m;var M=[];if(p){if(o=!1,(w+d.autoSkipPadding)*a.ticks.length>a.width-(a.paddingLeft+a.paddingRight)&&(o=1+Math.floor((w+d.autoSkipPadding)*a.ticks.length/(a.width-(a.paddingLeft+a.paddingRight)))),s&&a.ticks.length>s)for(;!o||a.ticks.length/(o||1)>s;)o||(o=1),o+=1;g||(o=!1)}var S="right"===r.position?a.left:a.right-y,D="right"===r.position?a.left+y:a.right,C="bottom"===r.position?a.top:a.bottom-y,P="bottom"===r.position?a.top+y:a.bottom;if(i.each(a.ticks,function(t,n){if(void 0!==t&&null!==t){var s=a.ticks.length===n+1,l=o>1&&n%o>0||n%o===0&&n+o>=a.ticks.length;if((!l||s)&&void 0!==t&&null!==t){var h,g,m,v;n===("undefined"!=typeof a.zeroLineIndex?a.zeroLineIndex:0)?(h=c.zeroLineWidth,g=c.zeroLineColor,m=c.zeroLineBorderDash,v=c.zeroLineBorderDashOffset):(h=i.getValueAtIndexOrDefault(c.lineWidth,n),g=i.getValueAtIndexOrDefault(c.color,n),m=i.getValueOrDefault(c.borderDash,u.borderDash),v=i.getValueOrDefault(c.borderDashOffset,u.borderDashOffset));var b,x,k,w,T,I,A,F,O,R,L="middle",V="middle";if(p){"bottom"===r.position?(V=f?"middle":"top",L=f?"right":"center",R=a.top+y):(V=f?"middle":"bottom",L=f?"left":"center",R=a.bottom-y);var W=a.getPixelForTick(n)+i.aliasPixel(h);O=a.getPixelForTick(n,c.offsetGridLines)+d.labelOffset,b=k=T=A=W,x=C,w=P,I=e.top,F=e.bottom}else{var Y,z="left"===r.position,N=d.padding;d.mirror?(L=z?"left":"right",Y=N):(L=z?"right":"left",Y=y+N),O=z?a.right-Y:a.left+Y;var B=a.getPixelForTick(n);B+=i.aliasPixel(h),R=a.getPixelForTick(n,c.offsetGridLines),b=S,k=D,T=e.left,A=e.right,x=w=I=F=B}M.push({tx1:b,ty1:x,tx2:k,ty2:w,x1:T,y1:I,x2:A,y2:F,labelX:O,labelY:R,glWidth:h,glColor:g,glBorderDash:m,glBorderDashOffset:v,rotation:-1*_,label:t,textBaseline:V,textAlign:L})}}}),i.each(M,function(t){if(c.display&&(l.save(),l.lineWidth=t.glWidth,l.strokeStyle=t.glColor,l.setLineDash&&(l.setLineDash(t.glBorderDash),l.lineDashOffset=t.glBorderDashOffset),l.beginPath(),c.drawTicks&&(l.moveTo(t.tx1,t.ty1),l.lineTo(t.tx2,t.ty2)),c.drawOnChartArea&&(l.moveTo(t.x1,t.y1),l.lineTo(t.x2,t.y2)),l.stroke(),l.restore()),d.display){l.save(),l.translate(t.labelX,t.labelY),l.rotate(t.rotation),l.font=v.font,l.textBaseline=t.textBaseline,l.textAlign=t.textAlign;var e=t.label;if(i.isArray(e))for(var n=0,a=0;n0)i=t.stepSize;else{var r=e.niceNum(n.max-n.min,!1);i=e.niceNum(r/(t.maxTicks-1),!0)}var o=Math.floor(n.min/i)*i,s=Math.ceil(n.max/i)*i;t.min&&t.max&&t.stepSize&&e.almostWhole((t.max-t.min)/t.stepSize,i/1e3)&&(o=t.min,s=t.max);var l=(s-o)/i;l=e.almostEquals(l,Math.round(l),i/1e3)?Math.round(l):Math.ceil(l),a.push(void 0!==t.min?t.min:o);for(var u=1;u3?i[2]-i[1]:i[1]-i[0];Math.abs(a)>1&&t!==Math.floor(t)&&(a=t-Math.floor(t));var r=e.log10(Math.abs(a)),o="";if(0!==t){var s=-1*Math.floor(r);s=Math.max(Math.min(s,20),0),o=t.toFixed(s)}else o="0";return o},logarithmic:function(t,n,i){var a=t/Math.pow(10,Math.floor(e.log10(t)));return 0===t?"0":1===a||2===a||5===a||0===n||n===i.length-1?t.toExponential():""}}}}},{}],34:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){var n=l.color(t);return n.alpha(e*n.alpha()).rgbaString()}function n(t,e){return e&&(l.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function i(t){var e=t._xScale,n=t._yScale||t._scale,i=t._index,a=t._datasetIndex;return{xLabel:e?e.getLabelForIndex(i,a):"",yLabel:n?n.getLabelForIndex(i,a):"",index:i,datasetIndex:a,x:t._model.x,y:t._model.y}}function a(e){var n=t.defaults.global,i=l.getValueOrDefault;return{xPadding:e.xPadding,yPadding:e.yPadding,xAlign:e.xAlign,yAlign:e.yAlign,bodyFontColor:e.bodyFontColor,_bodyFontFamily:i(e.bodyFontFamily,n.defaultFontFamily),_bodyFontStyle:i(e.bodyFontStyle,n.defaultFontStyle),_bodyAlign:e.bodyAlign,bodyFontSize:i(e.bodyFontSize,n.defaultFontSize),bodySpacing:e.bodySpacing,titleFontColor:e.titleFontColor,_titleFontFamily:i(e.titleFontFamily,n.defaultFontFamily),_titleFontStyle:i(e.titleFontStyle,n.defaultFontStyle),titleFontSize:i(e.titleFontSize,n.defaultFontSize),_titleAlign:e.titleAlign,titleSpacing:e.titleSpacing,titleMarginBottom:e.titleMarginBottom,footerFontColor:e.footerFontColor,_footerFontFamily:i(e.footerFontFamily,n.defaultFontFamily),_footerFontStyle:i(e.footerFontStyle,n.defaultFontStyle),footerFontSize:i(e.footerFontSize,n.defaultFontSize),_footerAlign:e.footerAlign,footerSpacing:e.footerSpacing,footerMarginTop:e.footerMarginTop,caretSize:e.caretSize,cornerRadius:e.cornerRadius,backgroundColor:e.backgroundColor,opacity:0,legendColorBackground:e.multiKeyBackground,displayColors:e.displayColors,borderColor:e.borderColor,borderWidth:e.borderWidth}}function r(t,e){var n=t._chart.ctx,i=2*e.yPadding,a=0,r=e.body,o=r.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);o+=e.beforeBody.length+e.afterBody.length;var s=e.title.length,u=e.footer.length,d=e.titleFontSize,c=e.bodyFontSize,h=e.footerFontSize;i+=s*d,i+=s?(s-1)*e.titleSpacing:0,i+=s?e.titleMarginBottom:0,i+=o*c,i+=o?(o-1)*e.bodySpacing:0,i+=u?e.footerMarginTop:0,i+=u*h,i+=u?(u-1)*e.footerSpacing:0;var f=0,g=function(t){a=Math.max(a,n.measureText(t).width+f)};return n.font=l.fontString(d,e._titleFontStyle,e._titleFontFamily),l.each(e.title,g),n.font=l.fontString(c,e._bodyFontStyle,e._bodyFontFamily),l.each(e.beforeBody.concat(e.afterBody),g),f=e.displayColors?c+2:0,l.each(r,function(t){l.each(t.before,g),l.each(t.lines,g),l.each(t.after,g)}),f=0,n.font=l.fontString(h,e._footerFontStyle,e._footerFontFamily),l.each(e.footer,g),a+=2*e.xPadding,{width:a,height:i}}function o(t,e){var n=t._model,i=t._chart,a=t._chart.chartArea,r="center",o="center";n.yi.height-e.height&&(o="bottom");var s,l,u,d,c,h=(a.left+a.right)/2,f=(a.top+a.bottom)/2;"center"===o?(s=function(t){return t<=h},l=function(t){return t>h}):(s=function(t){return t<=e.width/2},l=function(t){return t>=i.width-e.width/2}),u=function(t){return t+e.width>i.width},d=function(t){return t-e.width<0},c=function(t){return t<=f?"top":"bottom"},s(n.x)?(r="left",u(n.x)&&(r="center",o=c(n.y))):l(n.x)&&(r="right",d(n.x)&&(r="center",o=c(n.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:r,yAlign:g.yAlign?g.yAlign:o}}function s(t,e,n){var i=t.x,a=t.y,r=t.caretSize,o=t.caretPadding,s=t.cornerRadius,l=n.xAlign,u=n.yAlign,d=r+o,c=s+o;return"right"===l?i-=e.width:"center"===l&&(i-=e.width/2),"top"===u?a+=d:a-="bottom"===u?e.height+d:e.height/2,"center"===u?"left"===l?i+=d:"right"===l&&(i-=d):"left"===l?i-=c:"right"===l&&(i+=c),{x:i,y:a}}var l=t.helpers;t.defaults.global.tooltips={enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:l.noop,title:function(t,e){var n="",i=e.labels,a=i?i.length:0;if(t.length>0){var r=t[0];r.xLabel?n=r.xLabel:a>0&&r.index0&&i.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n={width:e.width,height:e.height},i={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,r=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&r&&(this.drawBackground(i,e,t,n,a),i.x+=e.xPadding,i.y+=e.yPadding,this.drawTitle(i,e,t,a),this.drawBody(i,e,t,a),this.drawFooter(i,e,t,a))}},handleEvent:function(t){var e=this,n=e._options,i=!1;if(e._lastActive=e._lastActive||[],"mouseout"===t.type?e._active=[]:e._active=e._chart.getElementsAtEventForMode(t,n.mode,n),i=!l.arrayEquals(e._active,e._lastActive),!i)return!1;if(e._lastActive=e._active,n.enabled||n.custom){e._eventPosition={x:t.x,y:t.y};var a=e._model;e.update(!0),e.pivot(),i|=a.x!==e._model.x||a.y!==e._model.y}return i}}),t.Tooltip.positioners={average:function(t){if(!t.length)return!1;var e,n,i=0,a=0,r=0;for(e=0,n=t.length;el;)r-=2*Math.PI;for(;r=s&&r<=l,d=o>=i.innerRadius&&o<=i.outerRadius;return u&&d}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,n=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,n=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},draw:function(){var t=this._chart.ctx,e=this._view,n=e.startAngle,i=e.endAngle;t.beginPath(),t.arc(e.x,e.y,e.outerRadius,n,i),t.arc(e.x,e.y,e.innerRadius,i,n,!0),t.closePath(),t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.fillStyle=e.backgroundColor,t.fill(),t.lineJoin="bevel",e.borderWidth&&t.stroke()}})}},{}],36:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global;t.defaults.global.elements.line={tension:.4,backgroundColor:n.defaultColor,borderWidth:3,borderColor:n.defaultColor,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0},t.elements.Line=t.Element.extend({draw:function(){var t,i,a,r,o=this,s=o._view,l=o._chart.ctx,u=s.spanGaps,d=o._children.slice(),c=n.elements.line,h=-1;for(o._loop&&d.length&&d.push(d[0]),l.save(),l.lineCap=s.borderCapStyle||c.borderCapStyle,l.setLineDash&&l.setLineDash(s.borderDash||c.borderDash),l.lineDashOffset=s.borderDashOffset||c.borderDashOffset,l.lineJoin=s.borderJoinStyle||c.borderJoinStyle,l.lineWidth=s.borderWidth||c.borderWidth,l.strokeStyle=s.borderColor||n.defaultColor,l.beginPath(),h=-1,t=0;te?1:-1,o=1,s=u.borderSkipped||"left"):(e=u.x-u.width/2,n=u.x+u.width/2,i=u.y,a=u.base,r=1,o=a>i?1:-1,s=u.borderSkipped||"bottom"),d){var c=Math.min(Math.abs(e-n),Math.abs(i-a));d=d>c?c:d;var h=d/2,f=e+("left"!==s?h*r:0),g=n+("right"!==s?-h*r:0),p=i+("top"!==s?h*o:0),m=a+("bottom"!==s?-h*o:0);f!==g&&(i=p,a=m),p!==m&&(e=f,n=g)}l.beginPath(),l.fillStyle=u.backgroundColor,l.strokeStyle=u.borderColor,l.lineWidth=d;var v=[[e,a],[e,i],[n,i],[n,a]],y=["bottom","left","top","right"],b=y.indexOf(s,0);b===-1&&(b=0);var x=t(0);l.moveTo(x[0],x[1]);for(var _=1;_<4;_++)x=t(_),l.lineTo(x[0],x[1]);l.fill(),d&&l.stroke()},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){var i=!1;if(this._view){var a=n(this);i=t>=a.left&&t<=a.right&&e>=a.top&&e<=a.bottom}return i},inLabelRange:function(t,i){var a=this;if(!a._view)return!1;var r=!1,o=n(a);return r=e(a)?t>=o.left&&t<=o.right:i>=o.top&&i<=o.bottom},inXRange:function(t){var e=n(this);return t>=e.left&&t<=e.right},inYRange:function(t){var e=n(this);return t>=e.top&&t<=e.bottom},getCenterPoint:function(){var t,n,i=this._view;return e(this)?(t=i.x,n=(i.y+i.base)/2):(t=(i.x+i.base)/2,n=i.y),{x:t,y:n}},getArea:function(){var t=this._view;return t.width*Math.abs(t.y-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}})}},{}],39:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){var n=l.getStyle(t,e),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?Number(i[1]):void 0}function n(t,n){var i=t.style,a=t.getAttribute("height"),r=t.getAttribute("width");if(t._chartjs={initial:{height:a,width:r,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",null===r||""===r){var o=e(t,"width");void 0!==o&&(t.width=o)}if(null===a||""===a)if(""===t.style.height)t.height=t.width/(n.options.aspectRatio||2);else{var s=e(t,"height");void 0!==o&&(t.height=s)}return t}function i(t,e,n,i,a){return{type:t,chart:e,native:a||null,x:void 0!==n?n:null,y:void 0!==i?i:null}}function a(t,e){var n=u[t.type]||t.type,a=l.getRelativePosition(t,e);return i(n,e,a.x,a.y,t)}function r(t){var e=document.createElement("iframe");return e.className="chartjs-hidden-iframe",e.style.cssText="display:block;overflow:hidden;border:0;margin:0;top:0;left:0;bottom:0;right:0;height:100%;width:100%;position:absolute;pointer-events:none;z-index:-1;",e.tabIndex=-1,l.addEvent(e,"load",function(){l.addEvent(e.contentWindow||e,"resize",t),t()}),e}function o(t,e,n){var a=t._chartjs={ticking:!1},o=function(){a.ticking||(a.ticking=!0,l.requestAnimFrame.call(window,function(){if(a.resizer)return a.ticking=!1,e(i("resize",n))}))};a.resizer=r(o),t.insertBefore(a.resizer,t.firstChild)}function s(t){if(t&&t._chartjs){var e=t._chartjs.resizer;e&&(e.parentNode.removeChild(e),t._chartjs.resizer=null),delete t._chartjs}}var l=t.helpers,u={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};return{acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(n(t,e),i):null},releaseContext:function(t){var e=t.canvas;if(e._chartjs){var n=e._chartjs.initial;["height","width"].forEach(function(t){var i=n[t];void 0===i||null===i?e.removeAttribute(t):e.setAttribute(t,i)}),l.each(n.style||{},function(t,n){e.style[n]=t}),e.width=e.width,delete e._chartjs}},addEventListener:function(t,e,n){var i=t.canvas;if("resize"===e)return void o(i.parentNode,n,t);var r=n._chartjs||(n._chartjs={}),s=r.proxies||(r.proxies={}),u=s[t.id+"_"+e]=function(e){n(a(e,t))};l.addEvent(i,e,u)},removeEventListener:function(t,e,n){var i=t.canvas;if("resize"===e)return void s(i.parentNode,n);var a=n._chartjs||{},r=a.proxies||{},o=r[t.id+"_"+e];o&&l.removeEvent(i,e,o)}}}},{}],40:[function(t,e,n){"use strict";var i=t(39);e.exports=function(t){t.platform={acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},t.helpers.extend(t.platform,i(t))}},{39:39}],41:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e,n){var i,a=t._model||{},r=a.fill;if(void 0===r&&(r=!!a.backgroundColor),r===!1||null===r)return!1;if(r===!0)return"origin";if(i=parseFloat(r,10),isFinite(i)&&Math.floor(i)===i)return"-"!==r[0]&&"+"!==r[0]||(i=e+i),!(i===e||i<0||i>=n)&&i;switch(r){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return r;default:return!1}}function n(t){var e,n=t.el._model||{},i=t.el._scale||{},a=t.fill,r=null;if(isFinite(a))return null;if("start"===a?r=void 0===n.scaleBottom?i.bottom:n.scaleBottom:"end"===a?r=void 0===n.scaleTop?i.top:n.scaleTop:void 0!==n.scaleZero?r=n.scaleZero:i.getBasePosition?r=i.getBasePosition():i.getBasePixel&&(r=i.getBasePixel()),void 0!==r&&null!==r){if(void 0!==r.x&&void 0!==r.y)return r;if("number"==typeof r&&isFinite(r))return e=i.isHorizontal(),{x:e?r:null,y:e?null:r}}return null}function i(t,e,n){var i,a=t[e],r=a.fill,o=[e];if(!n)return r;for(;r!==!1&&o.indexOf(r)===-1;){if(!isFinite(r))return r;if(i=t[r],!i)return!1;if(i.visible)return r;o.push(r),r=i.fill}return!1}function a(t){var e=t.fill,n="dataset";return e===!1?null:(isFinite(e)||(n="boundary"),d[n](t))}function r(t){return t&&!t.skip}function o(t,e,n,i,a){var r;if(i&&a){for(t.moveTo(e[0].x,e[0].y),r=1;r0;--r)u.canvas.lineTo(t,n[r],n[r-1],!0)}}function s(t,e,n,i,a,s){var l,u,d,c,h,f,g,p=e.length,m=i.spanGaps,v=[],y=[],b=0,x=0;for(t.beginPath(),l=0,u=p+!!s;l=n.width&&(y+=d+r.padding,v[v.length]=n.left),g[i]={left:0,top:0,width:o,height:d},v[v.length-1]+=o+r.padding}),p.height+=y}else{var b=r.padding,x=n.columnWidths=[],_=r.padding,k=0,w=0,M=d+b;i.each(n.legendItems,function(t,n){var i=e(r,d),a=i+d/2+s.measureText(t.text).width;w+M>p.height&&(_+=k+r.padding,x.push(k),k=0,w=0),k=Math.max(k,a),w+=M,g[n]={left:0,top:0,width:a,height:d}}),_+=k,x.push(k),p.width+=_}n.width=p.width,n.height=p.height},afterFit:r,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var n=this,a=n.options,r=a.labels,o=t.defaults.global,s=o.elements.line,l=n.width,u=n.lineWidths;if(a.display){var d,c=n.ctx,h=i.getValueOrDefault,f=h(r.fontColor,o.defaultFontColor),g=h(r.fontSize,o.defaultFontSize),p=h(r.fontStyle,o.defaultFontStyle),m=h(r.fontFamily,o.defaultFontFamily),v=i.fontString(g,p,m);c.textAlign="left",c.textBaseline="top",c.lineWidth=.5,c.strokeStyle=f,c.fillStyle=f,c.font=v;var y=e(r,g),b=n.legendHitBoxes,x=function(e,n,i){if(!(isNaN(y)||y<=0)){c.save(),c.fillStyle=h(i.fillStyle,o.defaultColor),c.lineCap=h(i.lineCap,s.borderCapStyle),c.lineDashOffset=h(i.lineDashOffset,s.borderDashOffset),c.lineJoin=h(i.lineJoin,s.borderJoinStyle),c.lineWidth=h(i.lineWidth,s.borderWidth),c.strokeStyle=h(i.strokeStyle,o.defaultColor);var r=0===h(i.lineWidth,s.borderWidth);if(c.setLineDash&&c.setLineDash(h(i.lineDash,s.borderDash)),a.labels&&a.labels.usePointStyle){var l=g*Math.SQRT2/2,u=l/Math.SQRT2,d=e+u,f=n+u;t.canvasHelpers.drawPoint(c,i.pointStyle,l,d,f)}else r||c.strokeRect(e,n,y,g),c.fillRect(e,n,y,g);c.restore()}},_=function(t,e,n,i){c.fillText(n.text,y+g/2+t,e),n.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(y+g/2+t,e+g/2),c.lineTo(y+g/2+t+i,e+g/2),c.stroke())},k=n.isHorizontal();d=k?{x:n.left+(l-u[0])/2,y:n.top+r.padding,line:0}:{x:n.left+r.padding,y:n.top+r.padding,line:0};var w=g+r.padding;i.each(n.legendItems,function(t,e){var i=c.measureText(t.text).width,a=y+g/2+i,o=d.x,s=d.y;k?o+a>=l&&(s=d.y+=w,d.line++,o=d.x=n.left+(l-u[d.line])/2):s+w>n.bottom&&(o=d.x=o+n.columnWidths[d.line]+r.padding,s=d.y=n.top+r.padding,d.line++),x(o,s,t),b[e].left=o,b[e].top=s,_(o,s,t,i),k?d.x+=a+r.padding:d.y+=w})}},handleEvent:function(t){var e=this,n=e.options,i="mouseup"===t.type?"click":t.type,a=!1;if("mousemove"===i){if(!n.onHover)return}else{if("click"!==i)return;if(!n.onClick)return}var r=t.x,o=t.y;if(r>=e.left&&r<=e.right&&o>=e.top&&o<=e.bottom)for(var s=e.legendHitBoxes,l=0;l=u.left&&r<=u.left+u.width&&o>=u.top&&o<=u.top+u.height){if("click"===i){n.onClick.call(e,t.native,e.legendItems[l]),a=!0;break}if("mousemove"===i){n.onHover.call(e,t.native,e.legendItems[l]),a=!0;break}}}return a}}),{id:"legend",beforeInit:function(t){var e=t.options.legend;e&&n(t,e)},beforeUpdate:function(e){var r=e.options.legend,o=e.legend;r?(r=i.configMerge(t.defaults.global.legend,r),o?(a.configure(e,o,r),o.options=r):n(e,r)):o&&(a.removeBox(e,o),delete e.legend)},afterEvent:function(t,e){var n=t.legend;n&&n.handleEvent(e)}}}},{}],43:[function(t,e,n){"use strict";e.exports=function(t){function e(e,n){var a=new t.Title({ctx:e.ctx,options:n,chart:e});i.configure(e,a,n),i.addBox(e,a),e.titleBlock=a}var n=t.helpers,i=t.layoutService,a=n.noop;return t.defaults.global.title={display:!1,position:"top",fullWidth:!0,weight:2e3,fontStyle:"bold",padding:10,text:""},t.Title=t.Element.extend({initialize:function(t){var e=this;n.extend(e,t),e.legendHitBoxes=[]},beforeUpdate:a,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:a,beforeSetDimensions:a,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:a,beforeBuildLabels:a,buildLabels:a,afterBuildLabels:a,beforeFit:a,fit:function(){var e=this,i=n.getValueOrDefault,a=e.options,r=t.defaults.global,o=a.display,s=i(a.fontSize,r.defaultFontSize),l=e.minSize;e.isHorizontal()?(l.width=e.maxWidth,l.height=o?s+2*a.padding:0):(l.width=o?s+2*a.padding:0,l.height=e.maxHeight),e.width=l.width,e.height=l.height},afterFit:a,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var e=this,i=e.ctx,a=n.getValueOrDefault,r=e.options,o=t.defaults.global;if(r.display){var s,l,u,d=a(r.fontSize,o.defaultFontSize),c=a(r.fontStyle,o.defaultFontStyle),h=a(r.fontFamily,o.defaultFontFamily),f=n.fontString(d,c,h),g=0,p=e.top,m=e.left,v=e.bottom,y=e.right;i.fillStyle=a(r.fontColor,o.defaultFontColor),i.font=f,e.isHorizontal()?(s=m+(y-m)/2,l=p+(v-p)/2,u=y-m):(s="left"===r.position?m+d/2:y-d/2,l=p+(v-p)/2,u=v-p,g=Math.PI*("left"===r.position?-.5:.5)),i.save(),i.translate(s,l),i.rotate(g),i.textAlign="center",i.textBaseline="middle",i.fillText(r.text,0,0,u),i.restore()}}}),{id:"title",beforeInit:function(t){var n=t.options.title;n&&e(t,n)},beforeUpdate:function(a){var r=a.options.title,o=a.titleBlock;r?(r=n.configMerge(t.defaults.global.title,r),o?(i.configure(a,o,r),o.options=r):e(a,r)):o&&(t.layoutService.removeBox(a,o),delete a.titleBlock)}}}},{}],44:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"bottom"},i=t.Scale.extend({getLabels:function(){var t=this.chart.data;return(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t=this,n=t.getLabels();t.minIndex=0,t.maxIndex=n.length-1;var i;void 0!==t.options.ticks.min&&(i=e.indexOf(n,t.options.ticks.min),t.minIndex=i!==-1?i:t.minIndex),void 0!==t.options.ticks.max&&(i=e.indexOf(n,t.options.ticks.max),t.maxIndex=i!==-1?i:t.maxIndex),t.min=n[t.minIndex],t.max=n[t.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var n=this,i=n.chart.data,a=n.isHorizontal();return i.yLabels&&!a?n.getRightValue(i.datasets[e].data[t]):n.ticks[t-n.minIndex]},getPixelForValue:function(t,e,n,i){var a,r=this,o=Math.max(r.maxIndex+1-r.minIndex-(r.options.gridLines.offsetGridLines?0:1),1);if(void 0!==t&&null!==t&&(a=r.isHorizontal()?t.x:t.y),void 0!==a||void 0!==t&&isNaN(e)){var s=r.getLabels();t=a||t;var l=s.indexOf(t);e=l!==-1?l:e}if(r.isHorizontal()){var u=r.width/o,d=u*(e-r.minIndex);return(r.options.gridLines.offsetGridLines&&i||r.maxIndex===r.minIndex&&i)&&(d+=u/2),r.left+Math.round(d)}var c=r.height/o,h=c*(e-r.minIndex);return r.options.gridLines.offsetGridLines&&i&&(h+=c/2),r.top+Math.round(h)},getPixelForTick:function(t,e){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null,e)},getValueForPixel:function(t){var e,n=this,i=Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),a=n.isHorizontal(),r=(a?n.width:n.height)/i;return t-=a?n.left:n.top,n.options.gridLines.offsetGridLines&&(t-=r/2),e=t<=0?0:Math.round(t/r)},getBasePixel:function(){return this.bottom}});t.scaleService.registerScaleType("category",i,n)}},{}],45:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:t.Ticks.formatters.linear}},i=t.LinearScaleBase.extend({determineDataLimits:function(){function t(t){return s?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=n.chart,r=a.data,o=r.datasets,s=n.isHorizontal(),l=0,u=1;n.min=null,n.max=null;var d=i.stacked;if(void 0===d&&e.each(o,function(e,n){if(!d){var i=a.getDatasetMeta(n);a.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(d=!0)}}),i.stacked||d){var c={};e.each(o,function(r,o){var s=a.getDatasetMeta(o),l=[s.type,void 0===i.stacked&&void 0===s.stack?o:"",s.stack].join(".");void 0===c[l]&&(c[l]={positiveValues:[],negativeValues:[]});var u=c[l].positiveValues,d=c[l].negativeValues;a.isDatasetVisible(o)&&t(s)&&e.each(r.data,function(t,e){var a=+n.getRightValue(t);isNaN(a)||s.data[e].hidden||(u[e]=u[e]||0,d[e]=d[e]||0,i.relativePoints?u[e]=100:a<0?d[e]+=a:u[e]+=a)})}),e.each(c,function(t){var i=t.positiveValues.concat(t.negativeValues),a=e.min(i),r=e.max(i);n.min=null===n.min?a:Math.min(n.min,a),n.max=null===n.max?r:Math.max(n.max,r)})}else e.each(o,function(i,r){var o=a.getDatasetMeta(r);a.isDatasetVisible(r)&&t(o)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||o.data[e].hidden||(null===n.min?n.min=i:in.max&&(n.max=i))})});n.min=isFinite(n.min)?n.min:l,n.max=isFinite(n.max)?n.max:u,this.handleTickRangeOptions()},getTickLimit:function(){var n,i=this,a=i.options.ticks;if(i.isHorizontal())n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.width/50));else{var r=e.getValueOrDefault(a.fontSize,t.defaults.global.defaultFontSize);n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.height/(2*r)))}return n},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e,n=this,i=n.start,a=+n.getRightValue(t),r=n.end-i;return n.isHorizontal()?(e=n.left+n.width/r*(a-i),Math.round(e)):(e=n.bottom-n.height/r*(a-i),Math.round(e))},getValueForPixel:function(t){var e=this,n=e.isHorizontal(),i=n?e.width:e.height,a=(n?t-e.left:e.bottom-t)/i;return e.start+(e.end-e.start)*a},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}});t.scaleService.registerScaleType("linear",i,n)}},{}],46:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=e.noop;t.LinearScaleBase=t.Scale.extend({handleTickRangeOptions:function(){var t=this,n=t.options,i=n.ticks;if(i.beginAtZero){var a=e.sign(t.min),r=e.sign(t.max);a<0&&r<0?t.max=0:a>0&&r>0&&(t.min=0)}void 0!==i.min?t.min=i.min:void 0!==i.suggestedMin&&(null===t.min?t.min=i.suggestedMin:t.min=Math.min(t.min,i.suggestedMin)),void 0!==i.max?t.max=i.max:void 0!==i.suggestedMax&&(null===t.max?t.max=i.suggestedMax:t.max=Math.max(t.max,i.suggestedMax)),t.min===t.max&&(t.max++,i.beginAtZero||t.min--)},getTickLimit:n,handleDirectionalChanges:n,buildTicks:function(){var n=this,i=n.options,a=i.ticks,r=n.getTickLimit();r=Math.max(2,r);var o={maxTicks:r,min:a.min,max:a.max,stepSize:e.getValueOrDefault(a.fixedStepSize,a.stepSize)},s=n.ticks=t.Ticks.generators.linear(o,n);n.handleDirectionalChanges(),n.max=e.max(s),n.min=e.min(s),a.reverse?(s.reverse(),n.start=n.max,n.end=n.min):(n.start=n.min,n.end=n.max)},convertTicksToLabels:function(){var e=this;e.ticksAsNumbers=e.ticks.slice(),e.zeroLineIndex=e.ticks.indexOf(0),t.Scale.prototype.convertTicksToLabels.call(e)}})}},{}],47:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:t.Ticks.formatters.logarithmic}},i=t.Scale.extend({determineDataLimits:function(){function t(t){return u?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=i.ticks,r=n.chart,o=r.data,s=o.datasets,l=e.getValueOrDefault,u=n.isHorizontal();n.min=null,n.max=null,n.minNotZero=null;var d=i.stacked;if(void 0===d&&e.each(s,function(e,n){if(!d){var i=r.getDatasetMeta(n);r.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(d=!0)}}),i.stacked||d){var c={};e.each(s,function(a,o){var s=r.getDatasetMeta(o),l=[s.type,void 0===i.stacked&&void 0===s.stack?o:"",s.stack].join(".");r.isDatasetVisible(o)&&t(s)&&(void 0===c[l]&&(c[l]=[]),e.each(a.data,function(t,e){var a=c[l],r=+n.getRightValue(t);isNaN(r)||s.data[e].hidden||(a[e]=a[e]||0,i.relativePoints?a[e]=100:a[e]+=r)}))}),e.each(c,function(t){var i=e.min(t),a=e.max(t);n.min=null===n.min?i:Math.min(n.min,i),n.max=null===n.max?a:Math.max(n.max,a)})}else e.each(s,function(i,a){var o=r.getDatasetMeta(a);r.isDatasetVisible(a)&&t(o)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||o.data[e].hidden||(null===n.min?n.min=i:in.max&&(n.max=i),0!==i&&(null===n.minNotZero||ia?{start:e-n-5,end:e}:{start:e,end:e+n+5}}function r(t){var r,o,s,l=n(t),u=Math.min(t.height/2,t.width/2),d={r:t.width,l:0,t:t.height,b:0},c={};t.ctx.font=l.font,t._pointLabelSizes=[];var h=e(t);for(r=0;rd.r&&(d.r=m.end,c.r=g),v.startd.b&&(d.b=v.end,c.b=g)}t.setReductions(u,d,c)}function o(t){var e=Math.min(t.height/2,t.width/2);t.drawingArea=Math.round(e),t.setCenterPoint(0,0,0,0)}function s(t){return 0===t||180===t?"center":t<180?"left":"right"}function l(t,e,n,i){if(f.isArray(e))for(var a=n.y,r=1.5*i,o=0;o270||t<90)&&(n.y-=e.h)}function d(t){var i=t.ctx,a=f.getValueOrDefault,r=t.options,o=r.angleLines,d=r.pointLabels;i.lineWidth=o.lineWidth,i.strokeStyle=o.color;var c=t.getDistanceFromCenterForValue(r.reverse?t.min:t.max),h=n(t);i.textBaseline="top";for(var p=e(t)-1;p>=0;p--){if(o.display){var m=t.getPointPosition(p,c);i.beginPath(),i.moveTo(t.xCenter,t.yCenter),i.lineTo(m.x,m.y),i.stroke(),i.closePath()}if(d.display){var v=t.getPointPosition(p,c+5),y=a(d.fontColor,g.defaultFontColor);i.font=h.font,i.fillStyle=y;var b=t.getIndexAngle(p),x=f.toDegrees(b);i.textAlign=s(x),u(x,t._pointLabelSizes[p],v),l(i,t.pointLabels[p]||"",v,h.size)}}}function c(t,n,i,a){var r=t.ctx;if(r.strokeStyle=f.getValueAtIndexOrDefault(n.color,a-1),r.lineWidth=f.getValueAtIndexOrDefault(n.lineWidth,a-1),t.options.gridLines.circular)r.beginPath(),r.arc(t.xCenter,t.yCenter,i,0,2*Math.PI),
+r.closePath(),r.stroke();else{var o=e(t);if(0===o)return;r.beginPath();var s=t.getPointPosition(0,i);r.moveTo(s.x,s.y);for(var l=1;l0&&n>0?e:0)},draw:function(){var t=this,e=t.options,n=e.gridLines,i=e.ticks,a=f.getValueOrDefault;if(e.display){var r=t.ctx,o=a(i.fontSize,g.defaultFontSize),s=a(i.fontStyle,g.defaultFontStyle),l=a(i.fontFamily,g.defaultFontFamily),u=f.fontString(o,s,l);f.each(t.ticks,function(s,l){if(l>0||e.reverse){var d=t.getDistanceFromCenterForValue(t.ticksAsNumbers[l]),h=t.yCenter-d;if(n.display&&0!==l&&c(t,n,d,l),i.display){var f=a(i.fontColor,g.defaultFontColor);if(r.font=u,i.showLabelBackdrop){var p=r.measureText(s).width;r.fillStyle=i.backdropColor,r.fillRect(t.xCenter-p/2-i.backdropPaddingX,h-o/2-i.backdropPaddingY,p+2*i.backdropPaddingX,o+2*i.backdropPaddingY)}r.textAlign="center",r.textBaseline="middle",r.fillStyle=f,r.fillText(s,t.xCenter,h)}}}),(e.angleLines.display||e.pointLabels.display)&&d(t)}}});t.scaleService.registerScaleType("radialLinear",m,p)}},{}],49:[function(t,e,n){"use strict";var i=t(6);i="function"==typeof i?i:window.moment,e.exports=function(t){function e(t,e){var n=t.options.time;if("string"==typeof n.parser)return i(e,n.parser);if("function"==typeof n.parser)return n.parser(e);if("function"==typeof e.getMonth||"number"==typeof e)return i(e);if(e.isValid&&e.isValid())return e;var a=n.format;return"string"!=typeof a&&a.call?(console.warn("options.time.format is deprecated and replaced by options.time.parser."),a(e)):i(e,a)}function n(t,e,n,i){for(var a,r=Object.keys(s),o=r.length,l=r.indexOf(t);li;c++)l=a.steps[c],o=Math.ceil(u/(r*l));else for(;o>i&&i>0;)++l,o=Math.ceil(u/(r*l));return l}function r(t,e,n){var a=[];if(t.maxTicks){var r=t.stepSize;a.push(void 0!==t.min?t.min:n.min);for(var o=i(n.min);o.add(r,t.unit).valueOf()0&&a.add(1,"week"),a=a.valueOf()):(n=i(e.min).startOf(t.unit).valueOf(),a=i(e.max).startOf(t.unit),e.max-a>0&&a.add(1,t.unit),a=a.valueOf()),r(t,e,{min:n,max:a})};var u=t.Scale.extend({initialize:function(){if(!i)throw new Error("Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com");t.Scale.prototype.initialize.call(this)},determineDataLimits:function(){var t,n=this,i=n.options.time,a=Number.MAX_SAFE_INTEGER,r=Number.MIN_SAFE_INTEGER,s=n.chart.data,l={labels:[],datasets:[]};o.each(s.labels,function(o,s){var u=e(n,o);u.isValid()&&(i.round&&u.startOf(i.round),t=u.valueOf(),a=Math.min(t,a),r=Math.max(t,r),l.labels[s]=t)}),o.each(s.datasets,function(s,u){var d=[];"object"==typeof s.data[0]&&null!==s.data[0]&&n.chart.isDatasetVisible(u)?o.each(s.data,function(o,s){var l=e(n,n.getRightValue(o));l.isValid()&&(i.round&&l.startOf(i.round),t=l.valueOf(),a=Math.min(t,a),r=Math.max(t,r),d[s]=t)}):d=l.labels.slice(),l.datasets[u]=d}),n.dataMin=a,n.dataMax=r,n._parsedData=l},buildTicks:function(){var i,r,s=this,l=s.options.time,u=s.dataMin,d=s.dataMax;if(l.min){var c=e(s,l.min);l.round&&c.round(l.round),i=c.valueOf()}l.max&&(r=e(s,l.max).valueOf());var h=s.getLabelCapacity(i||u),f=l.unit||n(l.minUnit,i||u,r||d,h);s.displayFormat=l.displayFormats[f];var g=l.stepSize||a(i||u,r||d,f,h);s.ticks=t.Ticks.generators.time({maxTicks:h,min:i,max:r,stepSize:g,unit:f,isoWeekday:l.isoWeekday},{min:u,max:d}),s.max=o.max(s.ticks),s.min=o.min(s.ticks)},getLabelForIndex:function(t,n){var i=this,a=i.chart.data.labels&&t 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;
+
+ this.valid = true;
+
+ 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(40)(Chart);
+require(22)(Chart);
+require(25)(Chart);
+require(30)(Chart);
+require(21)(Chart);
+require(23)(Chart);
+require(24)(Chart);
+require(29)(Chart);
+require(32)(Chart);
+require(33)(Chart);
+require(31)(Chart);
+require(27)(Chart);
+require(34)(Chart);
+
+require(35)(Chart);
+require(36)(Chart);
+require(37)(Chart);
+require(38)(Chart);
+
+require(46)(Chart);
+require(44)(Chart);
+require(45)(Chart);
+require(47)(Chart);
+require(48)(Chart);
+require(49)(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);
+
+// Loading built-it plugins
+var plugins = [];
+
+plugins.push(
+ require(41)(Chart),
+ require(42)(Chart),
+ require(43)(Chart)
+);
+
+Chart.plugins.register(plugins);
+
+module.exports = Chart;
+if (typeof window !== 'undefined') {
+ window.Chart = 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,"40":40,"41":41,"42":42,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"49":49,"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() {
+ var me = this;
+ var meta;
+
+ Chart.DatasetController.prototype.initialize.apply(me, arguments);
+
+ meta = me.getMeta();
+ meta.stack = me.getDataset().stack;
+ meta.bar = true;
+ },
+
+ update: function(reset) {
+ var me = this;
+ var elements = me.getMeta().data;
+ var i, ilen;
+
+ me._ruler = me.getRuler();
+
+ for (i = 0, ilen = elements.length; i < ilen; ++i) {
+ me.updateElement(elements[i], i, reset);
+ }
+ },
+
+ updateElement: function(rectangle, index, reset) {
+ var me = this;
+ var chart = me.chart;
+ var meta = me.getMeta();
+ var dataset = me.getDataset();
+ var custom = rectangle.custom || {};
+ var rectangleOptions = chart.options.elements.rectangle;
+
+ rectangle._xScale = me.getScaleForId(meta.xAxisID);
+ rectangle._yScale = me.getScaleForId(meta.yAxisID);
+ rectangle._datasetIndex = me.index;
+ rectangle._index = index;
+
+ rectangle._model = {
+ datasetLabel: dataset.label,
+ label: chart.data.labels[index],
+ borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
+ backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
+ borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
+ borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
+ };
+
+ me.updateElementGeometry(rectangle, index, reset);
+
+ rectangle.pivot();
+ },
+
+ /**
+ * @private
+ */
+ updateElementGeometry: function(rectangle, index, reset) {
+ var me = this;
+ var model = rectangle._model;
+ var vscale = me.getValueScale();
+ var base = vscale.getBasePixel();
+ var horizontal = vscale.isHorizontal();
+ var ruler = me._ruler || me.getRuler();
+ var vpixels = me.calculateBarValuePixels(me.index, index);
+ var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
+
+ model.horizontal = horizontal;
+ model.base = reset? base : vpixels.base;
+ model.x = horizontal? reset? base : vpixels.head : ipixels.center;
+ model.y = horizontal? ipixels.center : reset? base : vpixels.head;
+ model.height = horizontal? ipixels.size : undefined;
+ model.width = horizontal? undefined : ipixels.size;
+ },
+
+ /**
+ * @private
+ */
+ getValueScaleId: function() {
+ return this.getMeta().yAxisID;
+ },
+
+ /**
+ * @private
+ */
+ getIndexScaleId: function() {
+ return this.getMeta().xAxisID;
+ },
+
+ /**
+ * @private
+ */
+ getValueScale: function() {
+ return this.getScaleForId(this.getValueScaleId());
+ },
+
+ /**
+ * @private
+ */
+ getIndexScale: function() {
+ return this.getScaleForId(this.getIndexScaleId());
+ },
+
+ /**
+ * Returns the effective number of stacks based on groups and bar visibility.
+ * @private
+ */
+ getStackCount: function(last) {
+ var me = this;
+ var chart = me.chart;
+ var scale = me.getIndexScale();
+ var stacked = scale.options.stacked;
+ var ilen = last === undefined? chart.data.datasets.length : last + 1;
+ var stacks = [];
+ var i, meta;
+
+ for (i = 0; i < ilen; ++i) {
+ meta = chart.getDatasetMeta(i);
+ if (meta.bar && chart.isDatasetVisible(i) &&
+ (stacked === false ||
+ (stacked === true && stacks.indexOf(meta.stack) === -1) ||
+ (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
+ stacks.push(meta.stack);
+ }
+ }
+
+ return stacks.length;
+ },
+
+ /**
+ * Returns the stack index for the given dataset based on groups and bar visibility.
+ * @private
+ */
+ getStackIndex: function(datasetIndex) {
+ return this.getStackCount(datasetIndex) - 1;
+ },
+
+ /**
+ * @private
+ */
+ getRuler: function() {
+ var me = this;
+ var scale = me.getIndexScale();
+ var options = scale.options;
+ var stackCount = me.getStackCount();
+ var fullSize = scale.isHorizontal()? scale.width : scale.height;
+ var tickSize = fullSize / scale.ticks.length;
+ var categorySize = tickSize * options.categoryPercentage;
+ var fullBarSize = categorySize / stackCount;
+ var barSize = fullBarSize * options.barPercentage;
+
+ barSize = Math.min(
+ helpers.getValueOrDefault(options.barThickness, barSize),
+ helpers.getValueOrDefault(options.maxBarThickness, Infinity));
+
+ return {
+ stackCount: stackCount,
+ tickSize: tickSize,
+ categorySize: categorySize,
+ categorySpacing: tickSize - categorySize,
+ fullBarSize: fullBarSize,
+ barSize: barSize,
+ barSpacing: fullBarSize - barSize,
+ scale: scale
+ };
+ },
+
+ /**
+ * Note: pixel values are not clamped to the scale area.
+ * @private
+ */
+ calculateBarValuePixels: function(datasetIndex, index) {
+ var me = this;
+ var chart = me.chart;
+ var meta = me.getMeta();
+ var scale = me.getValueScale();
+ var datasets = chart.data.datasets;
+ var value = Number(datasets[datasetIndex].data[index]);
+ var stacked = scale.options.stacked;
+ var stack = meta.stack;
+ var start = 0;
+ var i, imeta, ivalue, base, head, size;
+
+ if (stacked || (stacked === undefined && stack !== undefined)) {
+ for (i = 0; i < datasetIndex; ++i) {
+ imeta = chart.getDatasetMeta(i);
+
+ if (imeta.bar &&
+ imeta.stack === stack &&
+ imeta.controller.getValueScaleId() === scale.id &&
+ chart.isDatasetVisible(i)) {
+
+ ivalue = Number(datasets[i].data[index]);
+ if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
+ start += ivalue;
+ }
+ }
+ }
+ }
+
+ base = scale.getPixelForValue(start);
+ head = scale.getPixelForValue(start + value);
+ size = (head - base) / 2;
+
+ return {
+ size: size,
+ base: base,
+ head: head,
+ center: head + size / 2
+ };
+ },
+
+ /**
+ * @private
+ */
+ calculateBarIndexPixels: function(datasetIndex, index, ruler) {
+ var me = this;
+ var scale = ruler.scale;
+ var isCombo = me.chart.isCombo;
+ var stackIndex = me.getStackIndex(datasetIndex);
+ var base = scale.getPixelForValue(null, index, datasetIndex, isCombo);
+ var size = ruler.barSize;
+
+ base -= isCombo? ruler.tickSize / 2 : 0;
+ base += ruler.fullBarSize * stackIndex;
+ base += ruler.categorySpacing / 2;
+ base += ruler.barSpacing / 2;
+
+ return {
+ size: size,
+ base: base,
+ head: base + size,
+ center: base + size / 2
+ };
+ },
+
+ draw: function() {
+ var me = this;
+ var chart = me.chart;
+ var elements = me.getMeta().data;
+ var dataset = me.getDataset();
+ var ilen = elements.length;
+ var i = 0;
+ var d;
+
+ helpers.canvas.clipArea(chart.ctx, chart.chartArea);
+
+ for (; i 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({
+ /**
+ * @private
+ */
+ getValueScaleId: function() {
+ return this.getMeta().xAxisID;
+ },
+
+ /**
+ * @private
+ */
+ getIndexScaleId: function() {
+ return this.getMeta().yAxisID;
+ }
+ });
+};
+
+},{}],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('');
+
+ var data = chart.data;
+ var datasets = data.datasets;
+ var labels = data.labels;
+
+ if (datasets.length) {
+ for (var i = 0; i < datasets[0].data.length; ++i) {
+ text.push(' ');
+ if (labels[i]) {
+ text.push(labels[i]);
+ }
+ text.push(' ');
+ }
+ }
+
+ text.push(' ');
+ return text.join('');
+ },
+ legend: {
+ labels: {
+ generateLabels: function(chart) {
+ var data = chart.data;
+ if (data.labels.length && data.datasets.length) {
+ return data.labels.map(function(label, i) {
+ var meta = chart.getDatasetMeta(0);
+ var ds = data.datasets[0];
+ var arc = meta.data[i];
+ var custom = arc && 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),
+ };
+
+ line.pivot();
+ }
+
+ // Update Points
+ for (i=0, ilen=points.length; i');
+
+ var data = chart.data;
+ var datasets = data.datasets;
+ var labels = data.labels;
+
+ if (datasets.length) {
+ for (var i = 0; i < datasets[0].data.length; ++i) {
+ text.push(' ');
+ if (labels[i]) {
+ text.push(labels[i]);
+ }
+ text.push(' ');
+ }
+ }
+
+ text.push('');
+ return text.join('');
+ },
+ legend: {
+ labels: {
+ generateLabels: function(chart) {
+ var data = chart.data;
+ if (data.labels.length && data.datasets.length) {
+ return data.labels.map(function(label, i) {
+ var meta = chart.getDatasetMeta(0);
+ var ds = data.datasets[0];
+ var arc = meta.data[i];
+ var custom = arc.custom || {};
+ var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
+ var arcOpts = chart.options.elements.arc;
+ var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
+ var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
+ var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
+
+ return {
+ text: label,
+ fillStyle: fill,
+ strokeStyle: stroke,
+ lineWidth: bw,
+ hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
+
+ // Extra data used for toggling the correct item
+ index: i
+ };
+ });
+ }
+ return [];
+ }
+ },
+
+ onClick: function(e, legendItem) {
+ var index = legendItem.index;
+ var chart = this.chart;
+ var i, ilen, meta;
+
+ for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+ meta = chart.getDatasetMeta(i);
+ meta.data[index].hidden = !meta.data[index].hidden;
+ }
+
+ chart.update();
+ }
+ },
+
+ // Need to override these to give a nice default
+ tooltips: {
+ callbacks: {
+ title: function() {
+ return '';
+ },
+ label: function(tooltipItem, data) {
+ return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
+ }
+ }
+ }
+ };
+
+ Chart.controllers.polarArea = Chart.DatasetController.extend({
+
+ dataElementType: Chart.elements.Arc,
+
+ linkScales: helpers.noop,
+
+ update: function(reset) {
+ var me = this;
+ var chart = me.chart;
+ var chartArea = chart.chartArea;
+ var meta = me.getMeta();
+ var opts = chart.options;
+ var arcOpts = opts.elements.arc;
+ var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
+ chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
+ chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
+ chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
+
+ me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
+ me.innerRadius = me.outerRadius - chart.radiusLength;
+
+ meta.count = me.countVisibleElements();
+
+ helpers.each(meta.data, function(arc, index) {
+ me.updateElement(arc, index, reset);
+ });
+ },
+
+ updateElement: function(arc, index, reset) {
+ var me = this;
+ var chart = me.chart;
+ var dataset = me.getDataset();
+ var opts = chart.options;
+ var animationOpts = opts.animation;
+ var scale = chart.scale;
+ var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
+ var labels = chart.data.labels;
+
+ var circumference = me.calculateCircumference(dataset.data[index]);
+ var centerX = scale.xCenter;
+ var centerY = scale.yCenter;
+
+ // If there is NaN data before us, we need to calculate the starting angle correctly.
+ // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
+ var visibleCount = 0;
+ var meta = me.getMeta();
+ for (var i = 0; i < index; ++i) {
+ if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
+ ++visibleCount;
+ }
+ }
+
+ // var negHalfPI = -0.5 * Math.PI;
+ var datasetStartAngle = opts.startAngle;
+ var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+ var startAngle = datasetStartAngle + (circumference * visibleCount);
+ var endAngle = startAngle + (arc.hidden ? 0 : circumference);
+
+ var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
+
+ helpers.extend(arc, {
+ // Utility
+ _datasetIndex: me.index,
+ _index: index,
+ _scale: scale,
+
+ // Desired view properties
+ _model: {
+ x: centerX,
+ y: centerY,
+ innerRadius: 0,
+ outerRadius: reset ? resetRadius : distance,
+ startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
+ endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
+ label: getValueAtIndexOrDefault(labels, index, labels[index])
+ }
+ });
+
+ // Apply border and fill style
+ me.removeHoverStyle(arc);
+
+ arc.pivot();
+ },
+
+ removeHoverStyle: function(arc) {
+ Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
+ },
+
+ countVisibleElements: function() {
+ var dataset = this.getDataset();
+ var meta = this.getMeta();
+ var count = 0;
+
+ helpers.each(meta.data, function(element, index) {
+ if (!isNaN(dataset.data[index]) && !element.hidden) {
+ count++;
+ }
+ });
+
+ return count;
+ },
+
+ calculateCircumference: function(value) {
+ var count = this.getMeta().count;
+ if (count > 0 && !isNaN(value)) {
+ return (2 * Math.PI) / count;
+ }
+ return 0;
+ }
+ });
+};
+
+},{}],20:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ Chart.defaults.radar = {
+ aspectRatio: 1,
+ scale: {
+ type: 'radialLinear'
+ },
+ elements: {
+ line: {
+ tension: 0 // no bezier in radar
+ }
+ }
+ };
+
+ Chart.controllers.radar = Chart.DatasetController.extend({
+
+ datasetElementType: Chart.elements.Line,
+
+ dataElementType: Chart.elements.Point,
+
+ linkScales: helpers.noop,
+
+ update: function(reset) {
+ var me = this;
+ var meta = me.getMeta();
+ var line = meta.dataset;
+ var points = meta.data;
+ var custom = line.custom || {};
+ var dataset = me.getDataset();
+ var lineElementOptions = me.chart.options.elements.line;
+ var scale = me.chart.scale;
+
+ // Compatibility: If the properties are defined with only the old name, use those values
+ if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
+ dataset.lineTension = dataset.tension;
+ }
+
+ helpers.extend(meta.dataset, {
+ // Utility
+ _datasetIndex: me.index,
+ _scale: scale,
+ // 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),
+ }
+ });
+
+ 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]);
+
+ // 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;
+ }
+
+ 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.pointHitRadius, 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();
+ });
+ },
+
+ 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.pointRadius, 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({
+ chart: null, // the animation associated chart instance
+ currentStep: 0, // 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,
+
+ /**
+ * @param {Chart} chart - The chart to animate.
+ * @param {Chart.Animation} animation - The animation that we will animate.
+ * @param {Number} duration - The animation duration in ms.
+ * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
+ */
+ addAnimation: function(chart, animation, duration, lazy) {
+ var animations = this.animations;
+ var i, ilen;
+
+ animation.chart = chart;
+
+ if (!lazy) {
+ chart.animating = true;
+ }
+
+ for (i=0, ilen=animations.length; i < ilen; ++i) {
+ if (animations[i].chart === chart) {
+ animations[i] = animation;
+ return;
+ }
+ }
+
+ animations.push(animation);
+
+ // If there are no animations queued, manually kickstart a digest, for lack of a better word
+ if (animations.length === 1) {
+ this.requestAnimationFrame();
+ }
+ },
+
+ cancelAnimation: function(chart) {
+ var index = helpers.findIndex(this.animations, function(animation) {
+ return animation.chart === chart;
+ });
+
+ if (index !== -1) {
+ this.animations.splice(index, 1);
+ chart.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();
+ });
+ }
+ },
+
+ /**
+ * @private
+ */
+ 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;
+ }
+
+ me.advance(1 + framesToDrop);
+
+ var endTime = Date.now();
+
+ me.dropFrames += (endTime - startTime) / me.frameDuration;
+
+ // Do we have more stuff to animate?
+ if (me.animations.length > 0) {
+ me.requestAnimationFrame();
+ }
+ },
+
+ /**
+ * @private
+ */
+ advance: function(count) {
+ var animations = this.animations;
+ var animation, chart;
+ var i = 0;
+
+ while (i < animations.length) {
+ animation = animations[i];
+ chart = animation.chart;
+
+ animation.currentStep = (animation.currentStep || 0) + count;
+ animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
+
+ helpers.callback(animation.render, [chart, animation], chart);
+ helpers.callback(animation.onAnimationProgress, [animation], chart);
+
+ if (animation.currentStep >= animation.numSteps) {
+ helpers.callback(animation.onAnimationComplete, [animation], chart);
+ chart.animating = false;
+ animations.splice(i, 1);
+ } else {
+ ++i;
+ }
+ }
+ }
+ };
+
+ /**
+ * Provided for backward compatibility, use Chart.Animation instead
+ * @prop Chart.Animation#animationObject
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+ Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
+ get: function() {
+ return this;
+ }
+ });
+
+ /**
+ * Provided for backward compatibility, use Chart.Animation#chart instead
+ * @prop Chart.Animation#chartInstance
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+ Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
+ get: function() {
+ return this.chart;
+ },
+ set: function(value) {
+ this.chart = value;
+ }
+ });
+
+};
+
+},{}],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, pointStyle.width, pointStyle.height);
+ 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();
+ };
+
+ helpers.lineTo = function(ctx, previous, target, flip) {
+ if (target.steppedLine) {
+ if (target.steppedLine === 'after') {
+ ctx.lineTo(previous.x, target.y);
+ } else {
+ ctx.lineTo(target.x, previous.y);
+ }
+ ctx.lineTo(target.x, target.y);
+ return;
+ }
+
+ if (!target.tension) {
+ ctx.lineTo(target.x, target.y);
+ return;
+ }
+
+ ctx.bezierCurveTo(
+ flip? previous.controlPointPreviousX : previous.controlPointNextX,
+ flip? previous.controlPointPreviousY : previous.controlPointNextY,
+ flip? target.controlPointNextX : target.controlPointPreviousX,
+ flip? target.controlPointNextY : target.controlPointPreviousY,
+ target.x,
+ target.y);
+ };
+
+ Chart.helpers.canvas = helpers;
+};
+
+},{}],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} 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;
+ }
+
+ function positionIsHorizontal(position) {
+ return position === 'top' || position === 'bottom';
+ }
+
+ helpers.extend(Chart.prototype, /** @lends Chart */ {
+ /**
+ * @private
+ */
+ construct: function(item, config) {
+ 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;
+
+ me.id = helpers.uid();
+ me.ctx = context;
+ me.canvas = canvas;
+ me.config = config;
+ me.width = width;
+ me.height = height;
+ me.aspectRatio = height? width / height : null;
+ me.options = config.options;
+ me._bufferedRender = false;
+
+ /**
+ * Provided for backward compatibility, Chart and Chart.Controller have been merged,
+ * the "instance" still need to be defined since it might be called from plugins.
+ * @prop Chart#chart
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ * @private
+ */
+ me.chart = me;
+ me.controller = me; // chart.chart.controller #inception
+
+ // Add the chart instance to the global namespace
+ Chart.instances[me.id] = me;
+
+ // Define alias to the config data: `chart.data === chart.config.data`
+ Object.defineProperty(me, 'data', {
+ get: function() {
+ return me.config.data;
+ },
+ set: function(value) {
+ me.config.data = value;
+ }
+ });
+
+ 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.initialize();
+ me.update();
+ },
+
+ /**
+ * @private
+ */
+ initialize: function() {
+ var me = this;
+
+ // Before init plugin notification
+ plugins.notify(me, 'beforeInit');
+
+ helpers.retinaScale(me);
+
+ 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);
+ return this;
+ },
+
+ stop: function() {
+ // Stops any current animation loop occurring
+ Chart.animationService.cancelAnimation(this);
+ return this;
+ },
+
+ resize: function(silent) {
+ var me = this;
+ var options = me.options;
+ var canvas = me.canvas;
+ var aspectRatio = (options.maintainAspectRatio && me.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 (me.width === newWidth && me.height === newHeight) {
+ return;
+ }
+
+ canvas.width = me.width = newWidth;
+ canvas.height = me.height = newHeight;
+ canvas.style.width = newWidth + 'px';
+ canvas.style.height = newHeight + 'px';
+
+ helpers.retinaScale(me);
+
+ 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', dposition: 'bottom'};
+ }),
+ (options.scales.yAxes || []).map(function(yAxisOptions) {
+ return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
+ })
+ );
+ }
+
+ if (options.scale) {
+ items.push({
+ options: options.scale,
+ dtype: 'radialLinear',
+ isDefault: true,
+ dposition: 'chartArea'
+ });
+ }
+
+ 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;
+ }
+
+ if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
+ scaleOptions.position = item.dposition;
+ }
+
+ var scale = new scaleClass({
+ id: scaleOptions.id,
+ options: scaleOptions,
+ ctx: me.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 {
+ var ControllerClass = Chart.controllers[meta.type];
+ if (ControllerClass === undefined) {
+ throw new Error('"' + meta.type + '" is not a chart type.');
+ }
+
+ meta.controller = new ControllerClass(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.width, this.height);
+
+ /**
+ * Provided for backward compatibility, use `afterLayout` instead.
+ * @method IPlugin#afterScaleUpdate
+ * @deprecated since version 2.5.0
+ * @todo remove at version 3
+ * @private
+ */
+ 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.updateDataset(i);
+ }
+
+ plugins.notify(me, 'afterDatasetsUpdate');
+ },
+
+ /**
+ * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
+ * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
+ * @private
+ */
+ updateDataset: function(index) {
+ var me = this;
+ var meta = me.getDatasetMeta(index);
+ var args = {
+ meta: meta,
+ index: index
+ };
+
+ if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
+ return;
+ }
+
+ meta.controller.update();
+
+ plugins.notify(me, 'afterDatasetUpdate', [args]);
+ },
+
+ render: function(duration, lazy) {
+ var me = this;
+
+ if (plugins.notify(me, 'beforeRender') === false) {
+ return;
+ }
+
+ var animationOptions = me.options.animation;
+ var onComplete = function(animation) {
+ plugins.notify(me, 'afterRender');
+ helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
+ };
+
+ if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
+ var animation = new Chart.Animation({
+ numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
+ easing: animationOptions.easing,
+
+ render: function(chart, animationObject) {
+ var easingFunction = helpers.easingEffects[animationObject.easing];
+ var currentStep = animationObject.currentStep;
+ var stepDecimal = currentStep / animationObject.numSteps;
+
+ chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
+ },
+
+ onAnimationProgress: animationOptions.onProgress,
+ onAnimationComplete: onComplete
+ });
+
+ Chart.animationService.addAnimation(me, animation, duration, lazy);
+ } else {
+ me.draw();
+
+ // See https://github.com/chartjs/Chart.js/issues/3781
+ onComplete(new Chart.Animation({numSteps: 0, chart: me}));
+ }
+
+ return me;
+ },
+
+ draw: function(easingValue) {
+ var me = this;
+
+ me.clear();
+
+ if (easingValue === undefined || easingValue === null) {
+ easingValue = 1;
+ }
+
+ me.transition(easingValue);
+
+ 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.draw();
+
+ plugins.notify(me, 'afterDraw', [easingValue]);
+ },
+
+ /**
+ * @private
+ */
+ transition: function(easingValue) {
+ var me = this;
+
+ for (var i=0, ilen=(me.data.datasets || []).length; i= 0; --i) {
+ if (me.isDatasetVisible(i)) {
+ me.drawDataset(i, easingValue);
+ }
+ }
+
+ plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
+ },
+
+ /**
+ * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
+ * hook, in which case, plugins will not be called on `afterDatasetDraw`.
+ * @private
+ */
+ drawDataset: function(index, easingValue) {
+ var me = this;
+ var meta = me.getDatasetMeta(index);
+ var args = {
+ meta: meta,
+ index: index,
+ easingValue: easingValue
+ };
+
+ if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
+ return;
+ }
+
+ meta.controller.draw(easingValue);
+
+ plugins.notify(me, 'afterDatasetDraw', [args]);
+ },
+
+ // 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 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,
+ _datasetIndex: me.index
+ });
+ },
+
+ createMetaData: function(index) {
+ var me = this;
+ var type = me.dataElementType;
+ return type && new type({
+ _chart: me.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 numMeta) {
+ me.insertElements(numMeta, numData - numMeta);
+ }
+ },
+
+ /**
+ * @private
+ */
+ insertElements: function(start, count) {
+ for (var i=0; i No Transition
+ if (!model || ease === 1) {
+ me._view = model;
+ me._start = null;
+ return me;
+ }
+
+ if (!view) {
+ view = me._view = {};
+ }
+
+ if (!start) {
+ start = me._start = {};
+ }
+
+ interpolate(start, view, model, ease);
+
+ 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;
+};
+
+},{"3":3}],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) {
+ return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
+ }
+ return index <= 0 ? collection[0] : collection[index - 1];
+ };
+ // Implementation of the nice number algorithm used in determining where axis labels will go
+ helpers.niceNum = function(range, round) {
+ var exponent = Math.floor(helpers.log10(range));
+ var fraction = range / Math.pow(10, exponent);
+ var niceFraction;
+
+ if (round) {
+ if (fraction < 1.5) {
+ niceFraction = 1;
+ } else if (fraction < 3) {
+ niceFraction = 2;
+ } else if (fraction < 7) {
+ niceFraction = 5;
+ } else {
+ niceFraction = 10;
+ }
+ } else if (fraction <= 1.0) {
+ niceFraction = 1;
+ } else if (fraction <= 2) {
+ niceFraction = 2;
+ } else if (fraction <= 5) {
+ niceFraction = 5;
+ } else {
+ niceFraction = 10;
+ }
+
+ return niceFraction * Math.pow(10, exponent);
+ };
+ // Easing functions adapted from Robert Penner's easing equations
+ // http://www.robertpenner.com/easing/
+ var easingEffects = helpers.easingEffects = {
+ linear: function(t) {
+ return t;
+ },
+ easeInQuad: function(t) {
+ return t * t;
+ },
+ easeOutQuad: function(t) {
+ return -1 * t * (t - 2);
+ },
+ easeInOutQuad: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t;
+ }
+ return -1 / 2 * ((--t) * (t - 2) - 1);
+ },
+ easeInCubic: function(t) {
+ return t * t * t;
+ },
+ easeOutCubic: function(t) {
+ return 1 * ((t = t / 1 - 1) * t * t + 1);
+ },
+ easeInOutCubic: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t;
+ }
+ return 1 / 2 * ((t -= 2) * t * t + 2);
+ },
+ easeInQuart: function(t) {
+ return t * t * t * t;
+ },
+ easeOutQuart: function(t) {
+ return -1 * ((t = t / 1 - 1) * t * t * t - 1);
+ },
+ easeInOutQuart: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t * t;
+ }
+ return -1 / 2 * ((t -= 2) * t * t * t - 2);
+ },
+ easeInQuint: function(t) {
+ return 1 * (t /= 1) * t * t * t * t;
+ },
+ easeOutQuint: function(t) {
+ return 1 * ((t = t / 1 - 1) * t * t * t * t + 1);
+ },
+ easeInOutQuint: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t * t * t;
+ }
+ return 1 / 2 * ((t -= 2) * t * t * t * t + 2);
+ },
+ easeInSine: function(t) {
+ return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1;
+ },
+ easeOutSine: function(t) {
+ return 1 * Math.sin(t / 1 * (Math.PI / 2));
+ },
+ easeInOutSine: function(t) {
+ return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1);
+ },
+ easeInExpo: function(t) {
+ return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1));
+ },
+ easeOutExpo: function(t) {
+ return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1);
+ },
+ easeInOutExpo: function(t) {
+ if (t === 0) {
+ return 0;
+ }
+ if (t === 1) {
+ return 1;
+ }
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * Math.pow(2, 10 * (t - 1));
+ }
+ return 1 / 2 * (-Math.pow(2, -10 * --t) + 2);
+ },
+ easeInCirc: function(t) {
+ if (t >= 1) {
+ return t;
+ }
+ return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1);
+ },
+ easeOutCirc: function(t) {
+ return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t);
+ },
+ easeInOutCirc: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return -1 / 2 * (Math.sqrt(1 - t * t) - 1);
+ }
+ return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1);
+ },
+ easeInElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1) === 1) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * 0.3;
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
+ },
+ easeOutElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1) === 1) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * 0.3;
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
+ },
+ easeInOutElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1 / 2) === 2) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * (0.3 * 1.5);
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ if (t < 1) {
+ return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
+ }
+ return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1;
+ },
+ easeInBack: function(t) {
+ var s = 1.70158;
+ return 1 * (t /= 1) * t * ((s + 1) * t - s);
+ },
+ easeOutBack: function(t) {
+ var s = 1.70158;
+ return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1);
+ },
+ easeInOutBack: function(t) {
+ var s = 1.70158;
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s));
+ }
+ return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
+ },
+ easeInBounce: function(t) {
+ return 1 - easingEffects.easeOutBounce(1 - t);
+ },
+ easeOutBounce: function(t) {
+ if ((t /= 1) < (1 / 2.75)) {
+ return 1 * (7.5625 * t * t);
+ } else if (t < (2 / 2.75)) {
+ return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
+ } else if (t < (2.5 / 2.75)) {
+ return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
+ }
+ return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
+ },
+ easeInOutBounce: function(t) {
+ if (t < 1 / 2) {
+ return easingEffects.easeInBounce(t * 2) * 0.5;
+ }
+ return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
+ }
+ };
+ // Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
+ helpers.requestAnimFrame = (function() {
+ if (typeof window === 'undefined') {
+ return function(callback) {
+ callback();
+ };
+ }
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback) {
+ return window.setTimeout(callback, 1000 / 60);
+ };
+ }());
+ // -- DOM methods
+ helpers.getRelativePosition = function(evt, chart) {
+ var mouseX, mouseY;
+ var e = evt.originalEvent || evt,
+ canvas = evt.currentTarget || evt.srcElement,
+ boundingRect = canvas.getBoundingClientRect();
+
+ var touches = e.touches;
+ if (touches && touches.length > 0) {
+ mouseX = touches[0].clientX;
+ mouseY = touches[0].clientY;
+
+ } else {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ }
+
+ // Scale mouse coordinates into canvas coordinates
+ // by following the pattern laid out by 'jerryj' in the comments of
+ // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
+ var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
+ var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
+ var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
+ var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
+ var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
+ var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
+
+ // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
+ // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
+ mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
+ mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
+
+ return {
+ x: mouseX,
+ y: mouseY
+ };
+
+ };
+ helpers.addEvent = function(node, eventType, method) {
+ if (node.addEventListener) {
+ node.addEventListener(eventType, method);
+ } else if (node.attachEvent) {
+ node.attachEvent('on' + eventType, method);
+ } else {
+ node['on' + eventType] = method;
+ }
+ };
+ helpers.removeEvent = function(node, eventType, handler) {
+ if (node.removeEventListener) {
+ node.removeEventListener(eventType, handler, false);
+ } else if (node.detachEvent) {
+ node.detachEvent('on' + eventType, handler);
+ } else {
+ node['on' + eventType] = helpers.noop;
+ }
+ };
+
+ // Private helper function to convert max-width/max-height values that may be percentages into a number
+ function parseMaxStyle(styleValue, node, parentProperty) {
+ var valueInPixels;
+ if (typeof(styleValue) === 'string') {
+ valueInPixels = parseInt(styleValue, 10);
+
+ if (styleValue.indexOf('%') !== -1) {
+ // percentage * size in dimension
+ valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
+ }
+ } else {
+ valueInPixels = styleValue;
+ }
+
+ return valueInPixels;
+ }
+
+ /**
+ * Returns if the given value contains an effective constraint.
+ * @private
+ */
+ function isConstrainedValue(value) {
+ return value !== undefined && value !== null && value !== 'none';
+ }
+
+ // Private helper to get a constraint dimension
+ // @param domNode : the node to check the constraint on
+ // @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
+ // @param percentageProperty : property of parent to use when calculating width as a percentage
+ // @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
+ function getConstraintDimension(domNode, maxStyle, percentageProperty) {
+ var view = document.defaultView;
+ var parentNode = domNode.parentNode;
+ var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
+ var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
+ var hasCNode = isConstrainedValue(constrainedNode);
+ var hasCContainer = isConstrainedValue(constrainedContainer);
+ var infinity = Number.POSITIVE_INFINITY;
+
+ if (hasCNode || hasCContainer) {
+ return Math.min(
+ hasCNode? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
+ hasCContainer? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
+ }
+
+ return 'none';
+ }
+ // returns Number or undefined if no constraint
+ helpers.getConstraintWidth = function(domNode) {
+ return getConstraintDimension(domNode, 'max-width', 'clientWidth');
+ };
+ // returns Number or undefined if no constraint
+ helpers.getConstraintHeight = function(domNode) {
+ return getConstraintDimension(domNode, 'max-height', 'clientHeight');
+ };
+ helpers.getMaximumWidth = function(domNode) {
+ var container = domNode.parentNode;
+ var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10);
+ var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10);
+ var w = container.clientWidth - paddingLeft - paddingRight;
+ var cw = helpers.getConstraintWidth(domNode);
+ return isNaN(cw)? w : Math.min(w, cw);
+ };
+ helpers.getMaximumHeight = function(domNode) {
+ var container = domNode.parentNode;
+ var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10);
+ var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10);
+ var h = container.clientHeight - paddingTop - paddingBottom;
+ var ch = helpers.getConstraintHeight(domNode);
+ return isNaN(ch)? h : Math.min(h, ch);
+ };
+ helpers.getStyle = function(el, property) {
+ return el.currentStyle ?
+ el.currentStyle[property] :
+ document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
+ };
+ helpers.retinaScale = function(chart) {
+ var pixelRatio = chart.currentDevicePixelRatio = window.devicePixelRatio || 1;
+ if (pixelRatio === 1) {
+ return;
+ }
+
+ var canvas = chart.canvas;
+ var height = chart.height;
+ var width = chart.width;
+
+ canvas.height = height * pixelRatio;
+ canvas.width = width * pixelRatio;
+ chart.ctx.scale(pixelRatio, pixelRatio);
+
+ // If no style has been set on the canvas, the render size is used as display size,
+ // making the chart visually bigger, so let's enforce it to the "correct" values.
+ // See https://github.com/chartjs/Chart.js/issues/3575
+ canvas.style.height = height + 'px';
+ canvas.style.width = width + 'px';
+ };
+ // -- Canvas methods
+ helpers.clear = function(chart) {
+ chart.ctx.clearRect(0, 0, chart.width, chart.height);
+ };
+ helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
+ return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
+ };
+ helpers.longestText = function(ctx, font, arrayOfThings, cache) {
+ cache = cache || {};
+ var data = cache.data = cache.data || {};
+ var gc = cache.garbageCollect = cache.garbageCollect || [];
+
+ if (cache.font !== font) {
+ data = cache.data = {};
+ gc = cache.garbageCollect = [];
+ cache.font = font;
+ }
+
+ ctx.font = font;
+ var longest = 0;
+ helpers.each(arrayOfThings, function(thing) {
+ // Undefined strings and arrays should not be measured
+ if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
+ longest = helpers.measureText(ctx, data, gc, longest, thing);
+ } else if (helpers.isArray(thing)) {
+ // if it is an array lets measure each element
+ // to do maybe simplify this function a bit so we can do this more recursively?
+ helpers.each(thing, function(nestedThing) {
+ // Undefined strings and arrays should not be measured
+ if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
+ longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
+ }
+ });
+ }
+ });
+
+ var gcLen = gc.length / 2;
+ if (gcLen > arrayOfThings.length) {
+ for (var i = 0; i < gcLen; i++) {
+ delete data[gc[i]];
+ }
+ gc.splice(0, gcLen);
+ }
+ return longest;
+ };
+ helpers.measureText = function(ctx, data, gc, longest, string) {
+ var textWidth = data[string];
+ if (!textWidth) {
+ textWidth = data[string] = ctx.measureText(string).width;
+ gc.push(string);
+ }
+ if (textWidth > longest) {
+ longest = textWidth;
+ }
+ return longest;
+ };
+ helpers.numberOfLabelLines = function(arrayOfThings) {
+ var numberOfLines = 1;
+ helpers.each(arrayOfThings, function(thing) {
+ if (helpers.isArray(thing)) {
+ if (thing.length > numberOfLines) {
+ numberOfLines = thing.length;
+ }
+ }
+ });
+ return numberOfLines;
+ };
+ helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) {
+ ctx.beginPath();
+ ctx.moveTo(x + radius, y);
+ ctx.lineTo(x + width - radius, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+ ctx.lineTo(x + radius, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+ ctx.lineTo(x, y + radius);
+ ctx.quadraticCurveTo(x, y, x + radius, y);
+ ctx.closePath();
+ };
+
+ helpers.color = !color?
+ function(value) {
+ console.error('Color.js not found!');
+ return value;
+ } :
+ function(value) {
+ /* global CanvasGradient */
+ if (value instanceof CanvasGradient) {
+ value = Chart.defaults.global.defaultColor;
+ }
+
+ return color(value);
+ };
+
+ helpers.isArray = Array.isArray?
+ function(obj) {
+ return Array.isArray(obj);
+ } :
+ function(obj) {
+ return Object.prototype.toString.call(obj) === '[object Array]';
+ };
+ // ! @see http://stackoverflow.com/a/14853974
+ helpers.arrayEquals = function(a0, a1) {
+ var i, ilen, v0, v1;
+
+ if (!a0 || !a1 || a0.length !== a1.length) {
+ return false;
+ }
+
+ for (i = 0, ilen=a0.length; i < ilen; ++i) {
+ v0 = a0[i];
+ v1 = a1[i];
+
+ if (v0 instanceof Array && v1 instanceof Array) {
+ if (!helpers.arrayEquals(v0, v1)) {
+ return false;
+ }
+ } else if (v0 !== v1) {
+ // NOTE: two different object instances will never be equal: {x:20} != {x:20}
+ return false;
+ }
+ }
+
+ return true;
+ };
+ helpers.callback = function(fn, args, thisArg) {
+ if (fn && typeof fn.call === 'function') {
+ fn.apply(thisArg, args);
+ }
+ };
+ helpers.getHoverColor = function(colorValue) {
+ /* global CanvasPattern */
+ return (colorValue instanceof CanvasPattern) ?
+ colorValue :
+ helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
+ };
+
+ /**
+ * Provided for backward compatibility, use Chart.helpers#callback instead.
+ * @function Chart.helpers#callCallback
+ * @deprecated since version 2.6.0
+ * @todo remove at version 3
+ */
+ helpers.callCallback = helpers.callback;
+};
+
+},{"3":3}],27:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+ var helpers = Chart.helpers;
+
+ /**
+ * Helper function to get relative position for an event
+ * @param {Event|IEvent} event - The event to get the position for
+ * @param {Chart} chart - The chart
+ * @returns {Point} the event position
+ */
+ function getRelativePosition(e, chart) {
+ if (e.native) {
+ return {
+ x: e.x,
+ y: e.y
+ };
+ }
+
+ return helpers.getRelativePosition(e, chart);
+ }
+
+ /**
+ * Helper function to traverse all of the visible elements in the chart
+ * @param chart {chart} the chart
+ * @param handler {Function} the callback to execute for each visible item
+ */
+ function parseVisibleItems(chart, handler) {
+ var datasets = chart.data.datasets;
+ var meta, i, j, ilen, jlen;
+
+ for (i = 0, ilen = datasets.length; i < ilen; ++i) {
+ if (!chart.isDatasetVisible(i)) {
+ continue;
+ }
+
+ meta = chart.getDatasetMeta(i);
+ for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
+ var element = meta.data[j];
+ if (!element._view.skip) {
+ handler(element);
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper function to get the items that intersect the event position
+ * @param items {ChartElement[]} elements to filter
+ * @param position {Point} the point to be nearest to
+ * @return {ChartElement[]} the nearest items
+ */
+ function getIntersectItems(chart, position) {
+ var elements = [];
+
+ parseVisibleItems(chart, function(element) {
+ if (element.inRange(position.x, position.y)) {
+ elements.push(element);
+ }
+ });
+
+ return elements;
+ }
+
+ /**
+ * Helper function to get the items nearest to the event position considering all visible items in teh chart
+ * @param chart {Chart} the chart to look at elements from
+ * @param position {Point} the point to be nearest to
+ * @param intersect {Boolean} if true, only consider items that intersect the position
+ * @param distanceMetric {Function} Optional function to provide the distance between
+ * @return {ChartElement[]} the nearest items
+ */
+ function getNearestItems(chart, position, intersect, distanceMetric) {
+ var minDistance = Number.POSITIVE_INFINITY;
+ var nearestItems = [];
+
+ if (!distanceMetric) {
+ distanceMetric = helpers.distanceBetweenPoints;
+ }
+
+ parseVisibleItems(chart, function(element) {
+ if (intersect && !element.inRange(position.x, position.y)) {
+ return;
+ }
+
+ var center = element.getCenterPoint();
+ var distance = distanceMetric(position, center);
+
+ if (distance < minDistance) {
+ nearestItems = [element];
+ minDistance = distance;
+ } else if (distance === minDistance) {
+ // Can have multiple items at the same distance in which case we sort by size
+ nearestItems.push(element);
+ }
+ });
+
+ return nearestItems;
+ }
+
+ function indexMode(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var distanceMetric = function(pt1, pt2) {
+ return Math.abs(pt1.x - pt2.x);
+ };
+ var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
+ var elements = [];
+
+ if (!items.length) {
+ return [];
+ }
+
+ chart.data.datasets.forEach(function(dataset, datasetIndex) {
+ if (chart.isDatasetVisible(datasetIndex)) {
+ var meta = chart.getDatasetMeta(datasetIndex),
+ element = meta.data[items[0]._index];
+
+ // don't count items that are skipped (null data)
+ if (element && !element._view.skip) {
+ elements.push(element);
+ }
+ }
+ });
+
+ return elements;
+ }
+
+ /**
+ * @interface IInteractionOptions
+ */
+ /**
+ * If true, only consider items that intersect the point
+ * @name IInterfaceOptions#boolean
+ * @type Boolean
+ */
+
+ /**
+ * Contains interaction related functions
+ * @namespace Chart.Interaction
+ */
+ Chart.Interaction = {
+ // Helper function for different modes
+ modes: {
+ single: function(chart, e) {
+ var position = getRelativePosition(e, chart);
+ var elements = [];
+
+ parseVisibleItems(chart, function(element) {
+ if (element.inRange(position.x, position.y)) {
+ elements.push(element);
+ return elements;
+ }
+ });
+
+ return elements.slice(0, 1);
+ },
+
+ /**
+ * @function Chart.Interaction.modes.label
+ * @deprecated since version 2.4.0
+ * @todo remove at version 3
+ * @private
+ */
+ label: indexMode,
+
+ /**
+ * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
+ * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
+ * @function Chart.Interaction.modes.index
+ * @since v2.4.0
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use during interaction
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ index: indexMode,
+
+ /**
+ * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
+ * If the options.intersect is false, we find the nearest item and return the items in that dataset
+ * @function Chart.Interaction.modes.dataset
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use during interaction
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ dataset: function(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false);
+
+ if (items.length > 0) {
+ items = chart.getDatasetMeta(items[0]._datasetIndex).data;
+ }
+
+ return items;
+ },
+
+ /**
+ * @function Chart.Interaction.modes.x-axis
+ * @deprecated since version 2.4.0. Use index mode and intersect == true
+ * @todo remove at version 3
+ * @private
+ */
+ 'x-axis': function(chart, e) {
+ return indexMode(chart, e, true);
+ },
+
+ /**
+ * Point mode returns all elements that hit test based on the event position
+ * of the event
+ * @function Chart.Interaction.modes.intersect
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ point: function(chart, e) {
+ var position = getRelativePosition(e, chart);
+ return getIntersectItems(chart, position);
+ },
+
+ /**
+ * nearest mode returns the element closest to the point
+ * @function Chart.Interaction.modes.intersect
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ nearest: function(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var nearestItems = getNearestItems(chart, position, options.intersect);
+
+ // We have multiple items at the same distance from the event. Now sort by smallest
+ if (nearestItems.length > 1) {
+ nearestItems.sort(function(a, b) {
+ var sizeA = a.getArea();
+ var sizeB = b.getArea();
+ var ret = sizeA - sizeB;
+
+ if (ret === 0) {
+ // if equal sort by dataset index
+ ret = a._datasetIndex - b._datasetIndex;
+ }
+
+ return ret;
+ });
+ }
+
+ // Return only 1 item
+ return nearestItems.slice(0, 1);
+ },
+
+ /**
+ * x mode returns the elements that hit-test at the current x coordinate
+ * @function Chart.Interaction.modes.x
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ x: function(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var items = [];
+ var intersectsItem = false;
+
+ parseVisibleItems(chart, function(element) {
+ if (element.inXRange(position.x)) {
+ items.push(element);
+ }
+
+ if (element.inRange(position.x, position.y)) {
+ intersectsItem = true;
+ }
+ });
+
+ // If we want to trigger on an intersect and we don't have any items
+ // that intersect the position, return nothing
+ if (options.intersect && !intersectsItem) {
+ items = [];
+ }
+ return items;
+ },
+
+ /**
+ * y mode returns the elements that hit-test at the current y coordinate
+ * @function Chart.Interaction.modes.y
+ * @param chart {chart} the chart we are returning items from
+ * @param e {Event} the event we are find things at
+ * @param options {IInteractionOptions} options to use
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
+ */
+ y: function(chart, e, options) {
+ var position = getRelativePosition(e, chart);
+ var items = [];
+ var intersectsItem = false;
+
+ parseVisibleItems(chart, function(element) {
+ if (element.inYRange(position.y)) {
+ items.push(element);
+ }
+
+ if (element.inRange(position.x, position.y)) {
+ intersectsItem = true;
+ }
+ });
+
+ // If we want to trigger on an intersect and we don't have any items
+ // that intersect the position, return nothing
+ if (options.intersect && !intersectsItem) {
+ items = [];
+ }
+ return items;
+ }
+ }
+ };
+};
+
+},{}],28:[function(require,module,exports){
+'use strict';
+
+module.exports = function() {
+
+ // Occupy the global variable of Chart, and create a simple base class
+ var Chart = function(item, config) {
+ this.construct(item, config);
+ return this;
+ };
+
+ // Globally expose the defaults to allow for user updating/changing
+ Chart.defaults = {
+ global: {
+ responsive: true,
+ responsiveAnimationDuration: 0,
+ maintainAspectRatio: true,
+ events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
+ hover: {
+ onHover: null,
+ mode: 'nearest',
+ intersect: true,
+ animationDuration: 400
+ },
+ onClick: null,
+ defaultColor: 'rgba(0,0,0,0.1)',
+ defaultFontColor: '#666',
+ defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+ defaultFontSize: 12,
+ defaultFontStyle: 'normal',
+ showLines: true,
+
+ // Element defaults defined in element extensions
+ elements: {},
+
+ // Legend callback string
+ legendCallback: function(chart) {
+ var text = [];
+ text.push('');
+ for (var i = 0; i < chart.data.datasets.length; i++) {
+ text.push(' ');
+ if (chart.data.datasets[i].label) {
+ text.push(chart.data.datasets[i].label);
+ }
+ text.push(' ');
+ }
+ text.push(' ');
+
+ return text.join('');
+ }
+ }
+ };
+
+ Chart.Chart = Chart;
+
+ return Chart;
+};
+
+},{}],29:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ function filterByPosition(array, position) {
+ return helpers.where(array, function(v) {
+ return v.position === position;
+ });
+ }
+
+ function sortByWeight(array, reverse) {
+ array.forEach(function(v, i) {
+ v._tmpIndex_ = i;
+ return v;
+ });
+ array.sort(function(a, b) {
+ var v0 = reverse ? b : a;
+ var v1 = reverse ? a : b;
+ return v0.weight === v1.weight ?
+ v0._tmpIndex_ - v1._tmpIndex_ :
+ v0.weight - v1.weight;
+ });
+ array.forEach(function(v) {
+ delete v._tmpIndex_;
+ });
+ }
+
+ /**
+ * @interface ILayoutItem
+ * @prop {String} position - The position of the item in the chart layout. Possible values are
+ * 'left', 'top', 'right', 'bottom', and 'chartArea'
+ * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
+ * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
+ * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
+ * @prop {Function} update - Takes two parameters: width and height. Returns size of item
+ * @prop {Function} getPadding - Returns an object with padding on the edges
+ * @prop {Number} width - Width of item. Must be valid after update()
+ * @prop {Number} height - Height of item. Must be valid after update()
+ * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
+ * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
+ */
+
+ // The layout service is very self explanatory. It's responsible for the layout within a chart.
+ // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
+ // It is this service's responsibility of carrying out that layout.
+ Chart.layoutService = {
+ defaults: {},
+
+ /**
+ * Register a box to a chart.
+ * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
+ * @param {Chart} chart - the chart to use
+ * @param {ILayoutItem} item - the item to add to be layed out
+ */
+ addBox: function(chart, item) {
+ if (!chart.boxes) {
+ chart.boxes = [];
+ }
+
+ // initialize item with default values
+ item.fullWidth = item.fullWidth || false;
+ item.position = item.position || 'top';
+ item.weight = item.weight || 0;
+
+ chart.boxes.push(item);
+ },
+
+ /**
+ * Remove a layoutItem from a chart
+ * @param {Chart} chart - the chart to remove the box from
+ * @param {Object} layoutItem - the item to remove from the layout
+ */
+ removeBox: function(chart, layoutItem) {
+ var index = chart.boxes? chart.boxes.indexOf(layoutItem) : -1;
+ if (index !== -1) {
+ chart.boxes.splice(index, 1);
+ }
+ },
+
+ /**
+ * Sets (or updates) options on the given `item`.
+ * @param {Chart} chart - the chart in which the item lives (or will be added to)
+ * @param {Object} item - the item to configure with the given options
+ * @param {Object} options - the new item options.
+ */
+ configure: function(chart, item, options) {
+ var props = ['fullWidth', 'position', 'weight'];
+ var ilen = props.length;
+ var i = 0;
+ var prop;
+
+ for (; i tickWidth && labelRotation < tickOpts.maxRotation) {
+ var angleRadians = helpers.toRadians(labelRotation);
+ cosRotation = Math.cos(angleRadians);
+ sinRotation = Math.sin(angleRadians);
+
+ if (sinRotation * originalLabelWidth > me.maxHeight) {
+ // go back one step
+ labelRotation--;
+ break;
+ }
+
+ labelRotation++;
+ labelWidth = cosRotation * originalLabelWidth;
+ }
+ }
+
+ me.labelRotation = labelRotation;
+ },
+ afterCalculateTickRotation: function() {
+ helpers.callback(this.options.afterCalculateTickRotation, [this]);
+ },
+
+ //
+
+ beforeFit: function() {
+ helpers.callback(this.options.beforeFit, [this]);
+ },
+ fit: function() {
+ var me = this;
+ // Reset
+ var minSize = me.minSize = {
+ width: 0,
+ height: 0
+ };
+
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+ var scaleLabelOpts = opts.scaleLabel;
+ var gridLineOpts = opts.gridLines;
+ var display = opts.display;
+ var isHorizontal = me.isHorizontal();
+
+ var tickFont = parseFontOptions(tickOpts);
+ var scaleLabelFontSize = parseFontOptions(scaleLabelOpts).size * 1.5;
+ var tickMarkLength = opts.gridLines.tickMarkLength;
+
+ // Width
+ if (isHorizontal) {
+ // subtract the margins to line up with the chartArea if we are a full width scale
+ minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
+ } else {
+ minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+ }
+
+ // height
+ if (isHorizontal) {
+ minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
+ } else {
+ minSize.height = me.maxHeight; // fill all the height
+ }
+
+ // Are we showing a title for the scale?
+ if (scaleLabelOpts.display && display) {
+ if (isHorizontal) {
+ minSize.height += scaleLabelFontSize;
+ } else {
+ minSize.width += scaleLabelFontSize;
+ }
+ }
+
+ // Don't bother fitting the ticks if we are not showing them
+ if (tickOpts.display && display) {
+ var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, me.ticks, me.longestTextCache);
+ var tallestLabelHeightInLines = helpers.numberOfLabelLines(me.ticks);
+ var lineSpace = tickFont.size * 0.5;
+
+ if (isHorizontal) {
+ // A horizontal axis is more constrained by the height.
+ me.longestLabelWidth = largestTextWidth;
+
+ var angleRadians = helpers.toRadians(me.labelRotation);
+ var cosRotation = Math.cos(angleRadians);
+ var sinRotation = Math.sin(angleRadians);
+
+ // TODO - improve this calculation
+ var labelHeight = (sinRotation * largestTextWidth)
+ + (tickFont.size * tallestLabelHeightInLines)
+ + (lineSpace * tallestLabelHeightInLines);
+
+ minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight);
+ me.ctx.font = tickFont.font;
+
+ var firstTick = me.ticks[0];
+ var firstLabelWidth = computeTextSize(me.ctx, firstTick, tickFont.font);
+
+ var lastTick = me.ticks[me.ticks.length - 1];
+ var lastLabelWidth = computeTextSize(me.ctx, lastTick, tickFont.font);
+
+ // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
+ // by the font height
+ if (me.labelRotation !== 0) {
+ me.paddingLeft = opts.position === 'bottom'? (cosRotation * firstLabelWidth) + 3: (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
+ me.paddingRight = opts.position === 'bottom'? (cosRotation * lineSpace) + 3: (cosRotation * lastLabelWidth) + 3;
+ } else {
+ me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
+ me.paddingRight = lastLabelWidth / 2 + 3;
+ }
+ } else {
+ // A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
+ // Account for padding
+
+ if (tickOpts.mirror) {
+ largestTextWidth = 0;
+ } else {
+ largestTextWidth += me.options.ticks.padding;
+ }
+ minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
+ me.paddingTop = tickFont.size / 2;
+ me.paddingBottom = tickFont.size / 2;
+ }
+ }
+
+ me.handleMargins();
+
+ me.width = minSize.width;
+ me.height = minSize.height;
+ },
+
+ /**
+ * Handle margins and padding interactions
+ * @private
+ */
+ handleMargins: function() {
+ var me = this;
+ if (me.margins) {
+ me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
+ me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
+ me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
+ me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
+ }
+ },
+
+ afterFit: function() {
+ helpers.callback(this.options.afterFit, [this]);
+ },
+
+ // Shared Methods
+ isHorizontal: function() {
+ return this.options.position === 'top' || this.options.position === 'bottom';
+ },
+ isFullWidth: function() {
+ return (this.options.fullWidth);
+ },
+
+ // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
+ getRightValue: function(rawValue) {
+ // Null and undefined values first
+ if (rawValue === null || typeof(rawValue) === 'undefined') {
+ return NaN;
+ }
+ // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
+ if (typeof(rawValue) === 'number' && !isFinite(rawValue)) {
+ return NaN;
+ }
+ // If it is in fact an object, dive in one more level
+ if (typeof(rawValue) === 'object') {
+ if ((rawValue instanceof Date) || (rawValue.isValid)) {
+ return rawValue;
+ }
+ return this.getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
+ }
+
+ // Value is good, return it
+ return rawValue;
+ },
+
+ // Used to get the value to display in the tooltip for the data at the given index
+ // function getLabelForIndex(index, datasetIndex)
+ getLabelForIndex: helpers.noop,
+
+ // Used to get data value locations. Value can either be an index or a numerical value
+ getPixelForValue: helpers.noop,
+
+ // Used to get the data value from a given pixel. This is the inverse of getPixelForValue
+ getValueForPixel: helpers.noop,
+
+ // Used for tick location, should
+ getPixelForTick: function(index, includeOffset) {
+ var me = this;
+ if (me.isHorizontal()) {
+ var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+ var tickWidth = innerWidth / Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+ var pixel = (tickWidth * index) + me.paddingLeft;
+
+ if (includeOffset) {
+ pixel += tickWidth / 2;
+ }
+
+ var finalVal = me.left + Math.round(pixel);
+ finalVal += me.isFullWidth() ? me.margins.left : 0;
+ return finalVal;
+ }
+ var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
+ return me.top + (index * (innerHeight / (me.ticks.length - 1)));
+ },
+
+ // Utility for getting the pixel location of a percentage of scale
+ getPixelForDecimal: function(decimal /* , includeOffset*/) {
+ var me = this;
+ if (me.isHorizontal()) {
+ var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
+ var valueOffset = (innerWidth * decimal) + me.paddingLeft;
+
+ var finalVal = me.left + Math.round(valueOffset);
+ finalVal += me.isFullWidth() ? me.margins.left : 0;
+ return finalVal;
+ }
+ return me.top + (decimal * me.height);
+ },
+
+ getBasePixel: function() {
+ return this.getPixelForValue(this.getBaseValue());
+ },
+
+ getBaseValue: function() {
+ var me = this;
+ var min = me.min;
+ var max = me.max;
+
+ return me.beginAtZero ? 0:
+ min < 0 && max < 0? max :
+ min > 0 && max > 0? min :
+ 0;
+ },
+
+ // Actually draw the scale on the canvas
+ // @param {rectangle} chartArea : the area of the chart to draw full grid lines on
+ draw: function(chartArea) {
+ var me = this;
+ var options = me.options;
+ if (!options.display) {
+ return;
+ }
+
+ var context = me.ctx;
+ var globalDefaults = Chart.defaults.global;
+ var optionTicks = options.ticks;
+ var gridLines = options.gridLines;
+ var scaleLabel = options.scaleLabel;
+
+ var isRotated = me.labelRotation !== 0;
+ var skipRatio;
+ var useAutoskipper = optionTicks.autoSkip;
+ var isHorizontal = me.isHorizontal();
+
+ // figure out the maximum number of gridlines to show
+ var maxTicks;
+ if (optionTicks.maxTicksLimit) {
+ maxTicks = optionTicks.maxTicksLimit;
+ }
+
+ var tickFontColor = helpers.getValueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
+ var tickFont = parseFontOptions(optionTicks);
+
+ var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
+
+ var scaleLabelFontColor = helpers.getValueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
+ var scaleLabelFont = parseFontOptions(scaleLabel);
+
+ var labelRotationRadians = helpers.toRadians(me.labelRotation);
+ var cosRotation = Math.cos(labelRotationRadians);
+ var longestRotatedLabel = me.longestLabelWidth * cosRotation;
+
+ // Make sure we draw text in the correct color and font
+ context.fillStyle = tickFontColor;
+
+ var itemsToDraw = [];
+
+ if (isHorizontal) {
+ skipRatio = false;
+
+ if ((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length > (me.width - (me.paddingLeft + me.paddingRight))) {
+ skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length) / (me.width - (me.paddingLeft + me.paddingRight)));
+ }
+
+ // if they defined a max number of optionTicks,
+ // increase skipRatio until that number is met
+ if (maxTicks && me.ticks.length > maxTicks) {
+ while (!skipRatio || me.ticks.length / (skipRatio || 1) > maxTicks) {
+ if (!skipRatio) {
+ skipRatio = 1;
+ }
+ skipRatio += 1;
+ }
+ }
+
+ if (!useAutoskipper) {
+ skipRatio = false;
+ }
+ }
+
+
+ var xTickStart = options.position === 'right' ? me.left : me.right - tl;
+ var xTickEnd = options.position === 'right' ? me.left + tl : me.right;
+ var yTickStart = options.position === 'bottom' ? me.top : me.bottom - tl;
+ var yTickEnd = options.position === 'bottom' ? me.top + tl : me.bottom;
+
+ helpers.each(me.ticks, function(label, index) {
+ // If the callback returned a null or undefined value, do not draw this line
+ if (label === undefined || label === null) {
+ return;
+ }
+
+ var isLastTick = me.ticks.length === index + 1;
+
+ // Since we always show the last tick,we need may need to hide the last shown one before
+ var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio >= me.ticks.length);
+ if (shouldSkip && !isLastTick || (label === undefined || label === null)) {
+ return;
+ }
+
+ var lineWidth, lineColor, borderDash, borderDashOffset;
+ if (index === (typeof me.zeroLineIndex !== 'undefined' ? me.zeroLineIndex : 0)) {
+ // Draw the first index specially
+ lineWidth = gridLines.zeroLineWidth;
+ lineColor = gridLines.zeroLineColor;
+ borderDash = gridLines.zeroLineBorderDash;
+ borderDashOffset = gridLines.zeroLineBorderDashOffset;
+ } else {
+ lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, index);
+ lineColor = helpers.getValueAtIndexOrDefault(gridLines.color, index);
+ borderDash = helpers.getValueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
+ borderDashOffset = helpers.getValueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
+ }
+
+ // Common properties
+ var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
+ var textAlign = 'middle';
+ var textBaseline = 'middle';
+
+ if (isHorizontal) {
+
+ if (options.position === 'bottom') {
+ // bottom
+ textBaseline = !isRotated? 'top':'middle';
+ textAlign = !isRotated? 'center': 'right';
+ labelY = me.top + tl;
+ } else {
+ // top
+ textBaseline = !isRotated? 'bottom':'middle';
+ textAlign = !isRotated? 'center': 'left';
+ labelY = me.bottom - tl;
+ }
+
+ var xLineValue = me.getPixelForTick(index) + helpers.aliasPixel(lineWidth); // xvalues for grid lines
+ labelX = me.getPixelForTick(index, gridLines.offsetGridLines) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
+
+ tx1 = tx2 = x1 = x2 = xLineValue;
+ ty1 = yTickStart;
+ ty2 = yTickEnd;
+ y1 = chartArea.top;
+ y2 = chartArea.bottom;
+ } else {
+ var isLeft = options.position === 'left';
+ var tickPadding = optionTicks.padding;
+ var labelXOffset;
+
+ if (optionTicks.mirror) {
+ textAlign = isLeft ? 'left' : 'right';
+ labelXOffset = tickPadding;
+ } else {
+ textAlign = isLeft ? 'right' : 'left';
+ labelXOffset = tl + tickPadding;
+ }
+
+ labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
+
+ var yLineValue = me.getPixelForTick(index); // xvalues for grid lines
+ yLineValue += helpers.aliasPixel(lineWidth);
+ labelY = me.getPixelForTick(index, gridLines.offsetGridLines);
+
+ tx1 = xTickStart;
+ tx2 = xTickEnd;
+ x1 = chartArea.left;
+ x2 = chartArea.right;
+ ty1 = ty2 = y1 = y2 = yLineValue;
+ }
+
+ itemsToDraw.push({
+ tx1: tx1,
+ ty1: ty1,
+ tx2: tx2,
+ ty2: ty2,
+ x1: x1,
+ y1: y1,
+ x2: x2,
+ y2: y2,
+ labelX: labelX,
+ labelY: labelY,
+ glWidth: lineWidth,
+ glColor: lineColor,
+ glBorderDash: borderDash,
+ glBorderDashOffset: borderDashOffset,
+ rotation: -1 * labelRotationRadians,
+ label: label,
+ textBaseline: textBaseline,
+ textAlign: textAlign
+ });
+ });
+
+ // Draw all of the tick labels, tick marks, and grid lines at the correct places
+ helpers.each(itemsToDraw, function(itemToDraw) {
+ if (gridLines.display) {
+ context.save();
+ context.lineWidth = itemToDraw.glWidth;
+ context.strokeStyle = itemToDraw.glColor;
+ if (context.setLineDash) {
+ context.setLineDash(itemToDraw.glBorderDash);
+ context.lineDashOffset = itemToDraw.glBorderDashOffset;
+ }
+
+ context.beginPath();
+
+ if (gridLines.drawTicks) {
+ context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
+ context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
+ }
+
+ if (gridLines.drawOnChartArea) {
+ context.moveTo(itemToDraw.x1, itemToDraw.y1);
+ context.lineTo(itemToDraw.x2, itemToDraw.y2);
+ }
+
+ context.stroke();
+ context.restore();
+ }
+
+ if (optionTicks.display) {
+ context.save();
+ context.translate(itemToDraw.labelX, itemToDraw.labelY);
+ context.rotate(itemToDraw.rotation);
+ context.font = tickFont.font;
+ context.textBaseline = itemToDraw.textBaseline;
+ context.textAlign = itemToDraw.textAlign;
+
+ var label = itemToDraw.label;
+ if (helpers.isArray(label)) {
+ for (var i = 0, y = 0; i < label.length; ++i) {
+ // We just make sure the multiline element is a string here..
+ context.fillText('' + label[i], 0, y);
+ // apply same lineSpacing as calculated @ L#320
+ y += (tickFont.size * 1.5);
+ }
+ } else {
+ context.fillText(label, 0, 0);
+ }
+ context.restore();
+ }
+ });
+
+ if (scaleLabel.display) {
+ // Draw the scale label
+ var scaleLabelX;
+ var scaleLabelY;
+ var rotation = 0;
+
+ if (isHorizontal) {
+ scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
+ scaleLabelY = options.position === 'bottom' ? me.bottom - (scaleLabelFont.size / 2) : me.top + (scaleLabelFont.size / 2);
+ } else {
+ var isLeft = options.position === 'left';
+ scaleLabelX = isLeft ? me.left + (scaleLabelFont.size / 2) : me.right - (scaleLabelFont.size / 2);
+ scaleLabelY = me.top + ((me.bottom - me.top) / 2);
+ rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
+ }
+
+ context.save();
+ context.translate(scaleLabelX, scaleLabelY);
+ context.rotate(rotation);
+ context.textAlign = 'center';
+ context.textBaseline = 'middle';
+ context.fillStyle = scaleLabelFontColor; // render in correct colour
+ context.font = scaleLabelFont.font;
+ context.fillText(scaleLabel.labelString, 0, 0);
+ context.restore();
+ }
+
+ if (gridLines.drawBorder) {
+ // Draw the line at the edge of the axis
+ context.lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, 0);
+ context.strokeStyle = helpers.getValueAtIndexOrDefault(gridLines.color, 0);
+ var x1 = me.left,
+ x2 = me.right,
+ y1 = me.top,
+ y2 = me.bottom;
+
+ var aliasPixel = helpers.aliasPixel(context.lineWidth);
+ if (isHorizontal) {
+ y1 = y2 = options.position === 'top' ? me.bottom : me.top;
+ y1 += aliasPixel;
+ y2 += aliasPixel;
+ } else {
+ x1 = x2 = options.position === 'left' ? me.right : me.left;
+ x1 += aliasPixel;
+ x2 += aliasPixel;
+ }
+
+ context.beginPath();
+ context.moveTo(x1, y1);
+ context.lineTo(x2, y2);
+ context.stroke();
+ }
+ }
+ });
+};
+
+},{}],32:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ Chart.scaleService = {
+ // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
+ // use the new chart options to grab the correct scale
+ constructors: {},
+ // Use a registration function so that we can move to an ES6 map when we no longer need to support
+ // old browsers
+
+ // Scale config defaults
+ defaults: {},
+ registerScaleType: function(type, scaleConstructor, defaults) {
+ this.constructors[type] = scaleConstructor;
+ this.defaults[type] = helpers.clone(defaults);
+ },
+ getScaleConstructor: function(type) {
+ return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
+ },
+ getScaleDefaults: function(type) {
+ // Return the scale defaults merged with the global settings so that we always use the latest ones
+ return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
+ },
+ updateScaleDefaults: function(type, additions) {
+ var defaults = this.defaults;
+ if (defaults.hasOwnProperty(type)) {
+ defaults[type] = helpers.extend(defaults[type], additions);
+ }
+ },
+ addScalesToLayout: function(chart) {
+ // Adds each scale to the chart.boxes array to be sized accordingly
+ helpers.each(chart.scales, function(scale) {
+ // Set ILayoutItem parameters for backwards compatibility
+ scale.fullWidth = scale.options.fullWidth;
+ scale.position = scale.options.position;
+ scale.weight = scale.options.weight;
+ Chart.layoutService.addBox(chart, scale);
+ });
+ }
+ };
+};
+
+},{}],33:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ /**
+ * Namespace to hold static tick generation functions
+ * @namespace Chart.Ticks
+ */
+ Chart.Ticks = {
+ /**
+ * Namespace to hold generators for different types of ticks
+ * @namespace Chart.Ticks.generators
+ */
+ generators: {
+ /**
+ * Interface for the options provided to the numeric tick generator
+ * @interface INumericTickGenerationOptions
+ */
+ /**
+ * The maximum number of ticks to display
+ * @name INumericTickGenerationOptions#maxTicks
+ * @type Number
+ */
+ /**
+ * The distance between each tick.
+ * @name INumericTickGenerationOptions#stepSize
+ * @type Number
+ * @optional
+ */
+ /**
+ * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum
+ * @name INumericTickGenerationOptions#min
+ * @type Number
+ * @optional
+ */
+ /**
+ * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum
+ * @name INumericTickGenerationOptions#max
+ * @type Number
+ * @optional
+ */
+
+ /**
+ * Generate a set of linear ticks
+ * @method Chart.Ticks.generators.linear
+ * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
+ * @param dataRange {IRange} the range of the data
+ * @returns {Array} array of tick values
+ */
+ linear: function(generationOptions, dataRange) {
+ var ticks = [];
+ // To get a "nice" value for the tick spacing, we will use the appropriately named
+ // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
+ // for details.
+
+ var spacing;
+ if (generationOptions.stepSize && generationOptions.stepSize > 0) {
+ spacing = generationOptions.stepSize;
+ } else {
+ var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
+ spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
+ }
+ var niceMin = Math.floor(dataRange.min / spacing) * spacing;
+ var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
+
+ // If min, max and stepSize is set and they make an evenly spaced scale use it.
+ if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
+ // If very close to our whole number, use it.
+ if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
+ niceMin = generationOptions.min;
+ niceMax = generationOptions.max;
+ }
+ }
+
+ var numSpaces = (niceMax - niceMin) / spacing;
+ // If very close to our rounded value, use it.
+ if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
+ numSpaces = Math.round(numSpaces);
+ } else {
+ numSpaces = Math.ceil(numSpaces);
+ }
+
+ // Put the values into the ticks array
+ ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
+ for (var j = 1; j < numSpaces; ++j) {
+ ticks.push(niceMin + (j * spacing));
+ }
+ ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
+
+ return ticks;
+ },
+
+ /**
+ * Generate a set of logarithmic ticks
+ * @method Chart.Ticks.generators.logarithmic
+ * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
+ * @param dataRange {IRange} the range of the data
+ * @returns {Array} array of tick values
+ */
+ logarithmic: function(generationOptions, dataRange) {
+ var ticks = [];
+ var getValueOrDefault = helpers.getValueOrDefault;
+
+ // Figure out what the max number of ticks we can support it is based on the size of
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+ // the graph
+ var tickVal = getValueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
+
+ var endExp = Math.floor(helpers.log10(dataRange.max));
+ var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
+ var exp;
+ var significand;
+
+ if (tickVal === 0) {
+ exp = Math.floor(helpers.log10(dataRange.minNotZero));
+ significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
+
+ ticks.push(tickVal);
+ tickVal = significand * Math.pow(10, exp);
+ } else {
+ exp = Math.floor(helpers.log10(tickVal));
+ significand = Math.floor(tickVal / Math.pow(10, exp));
+ }
+
+ do {
+ ticks.push(tickVal);
+
+ ++significand;
+ if (significand === 10) {
+ significand = 1;
+ ++exp;
+ }
+
+ tickVal = significand * Math.pow(10, exp);
+ } while (exp < endExp || (exp === endExp && significand < endSignificand));
+
+ var lastTick = getValueOrDefault(generationOptions.max, tickVal);
+ ticks.push(lastTick);
+
+ return ticks;
+ }
+ },
+
+ /**
+ * Namespace to hold formatters for different types of ticks
+ * @namespace Chart.Ticks.formatters
+ */
+ formatters: {
+ /**
+ * Formatter for value labels
+ * @method Chart.Ticks.formatters.values
+ * @param value the value to display
+ * @return {String|Array} the label to display
+ */
+ values: function(value) {
+ return helpers.isArray(value) ? value : '' + value;
+ },
+
+ /**
+ * Formatter for linear numeric ticks
+ * @method Chart.Ticks.formatters.linear
+ * @param tickValue {Number} the value to be formatted
+ * @param index {Number} the position of the tickValue parameter in the ticks array
+ * @param ticks {Array} the list of ticks being converted
+ * @return {String} string representation of the tickValue parameter
+ */
+ linear: function(tickValue, index, ticks) {
+ // If we have lots of ticks, don't use the ones
+ var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
+
+ // If we have a number like 2.5 as the delta, figure out how many decimal places we need
+ if (Math.abs(delta) > 1) {
+ if (tickValue !== Math.floor(tickValue)) {
+ // not an integer
+ delta = tickValue - Math.floor(tickValue);
+ }
+ }
+
+ var logDelta = helpers.log10(Math.abs(delta));
+ var tickString = '';
+
+ if (tickValue !== 0) {
+ var numDecimal = -1 * Math.floor(logDelta);
+ numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
+ tickString = tickValue.toFixed(numDecimal);
+ } else {
+ tickString = '0'; // never show decimal places for 0
+ }
+
+ return tickString;
+ },
+
+ logarithmic: function(tickValue, index, ticks) {
+ var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));
+
+ if (tickValue === 0) {
+ return '0';
+ } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
+ return tickValue.toExponential();
+ }
+ return '';
+ }
+ }
+ };
+};
+
+},{}],34:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ /**
+ * Helper method to merge the opacity into a color
+ */
+ function mergeOpacity(colorString, opacity) {
+ var color = helpers.color(colorString);
+ return color.alpha(opacity * color.alpha()).rgbaString();
+ }
+
+ Chart.defaults.global.tooltips = {
+ enabled: true,
+ custom: null,
+ mode: 'nearest',
+ position: 'average',
+ intersect: true,
+ backgroundColor: 'rgba(0,0,0,0.8)',
+ titleFontStyle: 'bold',
+ titleSpacing: 2,
+ titleMarginBottom: 6,
+ titleFontColor: '#fff',
+ titleAlign: 'left',
+ bodySpacing: 2,
+ bodyFontColor: '#fff',
+ bodyAlign: 'left',
+ footerFontStyle: 'bold',
+ footerSpacing: 2,
+ footerMarginTop: 6,
+ footerFontColor: '#fff',
+ footerAlign: 'left',
+ yPadding: 6,
+ xPadding: 6,
+ caretPadding: 2,
+ caretSize: 5,
+ cornerRadius: 6,
+ multiKeyBackground: '#fff',
+ displayColors: true,
+ borderColor: 'rgba(0,0,0,0)',
+ borderWidth: 0,
+ callbacks: {
+ // Args are: (tooltipItems, data)
+ beforeTitle: helpers.noop,
+ title: function(tooltipItems, data) {
+ // Pick first xLabel for now
+ var title = '';
+ var labels = data.labels;
+ var labelCount = labels ? labels.length : 0;
+
+ if (tooltipItems.length > 0) {
+ var item = tooltipItems[0];
+
+ if (item.xLabel) {
+ title = item.xLabel;
+ } else if (labelCount > 0 && item.index < labelCount) {
+ title = labels[item.index];
+ }
+ }
+
+ return title;
+ },
+ afterTitle: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ beforeBody: helpers.noop,
+
+ // Args are: (tooltipItem, data)
+ beforeLabel: helpers.noop,
+ label: function(tooltipItem, data) {
+ var label = data.datasets[tooltipItem.datasetIndex].label || '';
+
+ if (label) {
+ label += ': ';
+ }
+ label += tooltipItem.yLabel;
+ return label;
+ },
+ labelColor: function(tooltipItem, chart) {
+ var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
+ var activeElement = meta.data[tooltipItem.index];
+ var view = activeElement._view;
+ return {
+ borderColor: view.borderColor,
+ backgroundColor: view.backgroundColor
+ };
+ },
+ afterLabel: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ afterBody: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ beforeFooter: helpers.noop,
+ footer: helpers.noop,
+ afterFooter: helpers.noop
+ }
+ };
+
+ // Helper to push or concat based on if the 2nd parameter is an array or not
+ function pushOrConcat(base, toPush) {
+ if (toPush) {
+ if (helpers.isArray(toPush)) {
+ // base = base.concat(toPush);
+ Array.prototype.push.apply(base, toPush);
+ } else {
+ base.push(toPush);
+ }
+ }
+
+ return base;
+ }
+
+ // Private helper to create a tooltip item model
+ // @param element : the chart element (point, arc, bar) to create the tooltip item for
+ // @return : new tooltip item
+ function createTooltipItem(element) {
+ var xScale = element._xScale;
+ var yScale = element._yScale || element._scale; // handle radar || polarArea charts
+ var index = element._index,
+ datasetIndex = element._datasetIndex;
+
+ return {
+ xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
+ yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
+ index: index,
+ datasetIndex: datasetIndex,
+ x: element._model.x,
+ y: element._model.y
+ };
+ }
+
+ /**
+ * Helper to get the reset model for the tooltip
+ * @param tooltipOpts {Object} the tooltip options
+ */
+ function getBaseModel(tooltipOpts) {
+ var globalDefaults = Chart.defaults.global;
+ var getValueOrDefault = helpers.getValueOrDefault;
+
+ return {
+ // Positioning
+ xPadding: tooltipOpts.xPadding,
+ yPadding: tooltipOpts.yPadding,
+ xAlign: tooltipOpts.xAlign,
+ yAlign: tooltipOpts.yAlign,
+
+ // Body
+ bodyFontColor: tooltipOpts.bodyFontColor,
+ _bodyFontFamily: getValueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
+ _bodyFontStyle: getValueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
+ _bodyAlign: tooltipOpts.bodyAlign,
+ bodyFontSize: getValueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
+ bodySpacing: tooltipOpts.bodySpacing,
+
+ // Title
+ titleFontColor: tooltipOpts.titleFontColor,
+ _titleFontFamily: getValueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
+ _titleFontStyle: getValueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
+ titleFontSize: getValueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
+ _titleAlign: tooltipOpts.titleAlign,
+ titleSpacing: tooltipOpts.titleSpacing,
+ titleMarginBottom: tooltipOpts.titleMarginBottom,
+
+ // Footer
+ footerFontColor: tooltipOpts.footerFontColor,
+ _footerFontFamily: getValueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
+ _footerFontStyle: getValueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
+ footerFontSize: getValueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
+ _footerAlign: tooltipOpts.footerAlign,
+ footerSpacing: tooltipOpts.footerSpacing,
+ footerMarginTop: tooltipOpts.footerMarginTop,
+
+ // Appearance
+ caretSize: tooltipOpts.caretSize,
+ cornerRadius: tooltipOpts.cornerRadius,
+ backgroundColor: tooltipOpts.backgroundColor,
+ opacity: 0,
+ legendColorBackground: tooltipOpts.multiKeyBackground,
+ displayColors: tooltipOpts.displayColors,
+ borderColor: tooltipOpts.borderColor,
+ borderWidth: tooltipOpts.borderWidth
+ };
+ }
+
+ /**
+ * Get the size of the tooltip
+ */
+ function getTooltipSize(tooltip, model) {
+ var ctx = tooltip._chart.ctx;
+
+ var height = model.yPadding * 2; // Tooltip Padding
+ var width = 0;
+
+ // Count of all lines in the body
+ var body = model.body;
+ var combinedBodyLength = body.reduce(function(count, bodyItem) {
+ return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
+ }, 0);
+ combinedBodyLength += model.beforeBody.length + model.afterBody.length;
+
+ var titleLineCount = model.title.length;
+ var footerLineCount = model.footer.length;
+ var titleFontSize = model.titleFontSize,
+ bodyFontSize = model.bodyFontSize,
+ footerFontSize = model.footerFontSize;
+
+ height += titleLineCount * titleFontSize; // Title Lines
+ height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
+ height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
+ height += combinedBodyLength * bodyFontSize; // Body Lines
+ height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
+ height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
+ height += footerLineCount * (footerFontSize); // Footer Lines
+ height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
+
+ // Title width
+ var widthPadding = 0;
+ var maxLineWidth = function(line) {
+ width = Math.max(width, ctx.measureText(line).width + widthPadding);
+ };
+
+ ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
+ helpers.each(model.title, maxLineWidth);
+
+ // Body width
+ ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
+ helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
+
+ // Body lines may include some extra width due to the color box
+ widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
+ helpers.each(body, function(bodyItem) {
+ helpers.each(bodyItem.before, maxLineWidth);
+ helpers.each(bodyItem.lines, maxLineWidth);
+ helpers.each(bodyItem.after, maxLineWidth);
+ });
+
+ // Reset back to 0
+ widthPadding = 0;
+
+ // Footer width
+ ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
+ helpers.each(model.footer, maxLineWidth);
+
+ // Add padding
+ width += 2 * model.xPadding;
+
+ return {
+ width: width,
+ height: height
+ };
+ }
+
+ /**
+ * Helper to get the alignment of a tooltip given the size
+ */
+ function determineAlignment(tooltip, size) {
+ var model = tooltip._model;
+ var chart = tooltip._chart;
+ var chartArea = tooltip._chart.chartArea;
+ var xAlign = 'center';
+ var yAlign = 'center';
+
+ if (model.y < size.height) {
+ yAlign = 'top';
+ } else if (model.y > (chart.height - size.height)) {
+ yAlign = 'bottom';
+ }
+
+ var lf, rf; // functions to determine left, right alignment
+ var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
+ var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
+ var midX = (chartArea.left + chartArea.right) / 2;
+ var midY = (chartArea.top + chartArea.bottom) / 2;
+
+ if (yAlign === 'center') {
+ lf = function(x) {
+ return x <= midX;
+ };
+ rf = function(x) {
+ return x > midX;
+ };
+ } else {
+ lf = function(x) {
+ return x <= (size.width / 2);
+ };
+ rf = function(x) {
+ return x >= (chart.width - (size.width / 2));
+ };
+ }
+
+ olf = function(x) {
+ return x + size.width > chart.width;
+ };
+ orf = function(x) {
+ return x - size.width < 0;
+ };
+ yf = function(y) {
+ return y <= midY ? 'top' : 'bottom';
+ };
+
+ if (lf(model.x)) {
+ xAlign = 'left';
+
+ // Is tooltip too wide and goes over the right side of the chart.?
+ if (olf(model.x)) {
+ xAlign = 'center';
+ yAlign = yf(model.y);
+ }
+ } else if (rf(model.x)) {
+ xAlign = 'right';
+
+ // Is tooltip too wide and goes outside left edge of canvas?
+ if (orf(model.x)) {
+ xAlign = 'center';
+ yAlign = yf(model.y);
+ }
+ }
+
+ var opts = tooltip._options;
+ return {
+ xAlign: opts.xAlign ? opts.xAlign : xAlign,
+ yAlign: opts.yAlign ? opts.yAlign : yAlign
+ };
+ }
+
+ /**
+ * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
+ */
+ function getBackgroundPoint(vm, size, alignment) {
+ // Background Position
+ var x = vm.x;
+ var y = vm.y;
+
+ var caretSize = vm.caretSize,
+ caretPadding = vm.caretPadding,
+ cornerRadius = vm.cornerRadius,
+ xAlign = alignment.xAlign,
+ yAlign = alignment.yAlign,
+ paddingAndSize = caretSize + caretPadding,
+ radiusAndPadding = cornerRadius + caretPadding;
+
+ if (xAlign === 'right') {
+ x -= size.width;
+ } else if (xAlign === 'center') {
+ x -= (size.width / 2);
+ }
+
+ if (yAlign === 'top') {
+ y += paddingAndSize;
+ } else if (yAlign === 'bottom') {
+ y -= size.height + paddingAndSize;
+ } else {
+ y -= (size.height / 2);
+ }
+
+ if (yAlign === 'center') {
+ if (xAlign === 'left') {
+ x += paddingAndSize;
+ } else if (xAlign === 'right') {
+ x -= paddingAndSize;
+ }
+ } else if (xAlign === 'left') {
+ x -= radiusAndPadding;
+ } else if (xAlign === 'right') {
+ x += radiusAndPadding;
+ }
+
+ return {
+ x: x,
+ y: y
+ };
+ }
+
+ Chart.Tooltip = Chart.Element.extend({
+ initialize: function() {
+ this._model = getBaseModel(this._options);
+ },
+
+ // Get the title
+ // Args are: (tooltipItem, data)
+ getTitle: function() {
+ var me = this;
+ var opts = me._options;
+ var callbacks = opts.callbacks;
+
+ var beforeTitle = callbacks.beforeTitle.apply(me, arguments),
+ title = callbacks.title.apply(me, arguments),
+ afterTitle = callbacks.afterTitle.apply(me, arguments);
+
+ var lines = [];
+ lines = pushOrConcat(lines, beforeTitle);
+ lines = pushOrConcat(lines, title);
+ lines = pushOrConcat(lines, afterTitle);
+
+ return lines;
+ },
+
+ // Args are: (tooltipItem, data)
+ getBeforeBody: function() {
+ var lines = this._options.callbacks.beforeBody.apply(this, arguments);
+ return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
+ },
+
+ // Args are: (tooltipItem, data)
+ getBody: function(tooltipItems, data) {
+ var me = this;
+ var callbacks = me._options.callbacks;
+ var bodyItems = [];
+
+ helpers.each(tooltipItems, function(tooltipItem) {
+ var bodyItem = {
+ before: [],
+ lines: [],
+ after: []
+ };
+ pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
+ pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
+ pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
+
+ bodyItems.push(bodyItem);
+ });
+
+ return bodyItems;
+ },
+
+ // Args are: (tooltipItem, data)
+ getAfterBody: function() {
+ var lines = this._options.callbacks.afterBody.apply(this, arguments);
+ return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
+ },
+
+ // Get the footer and beforeFooter and afterFooter lines
+ // Args are: (tooltipItem, data)
+ getFooter: function() {
+ var me = this;
+ var callbacks = me._options.callbacks;
+
+ var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
+ var footer = callbacks.footer.apply(me, arguments);
+ var afterFooter = callbacks.afterFooter.apply(me, arguments);
+
+ var lines = [];
+ lines = pushOrConcat(lines, beforeFooter);
+ lines = pushOrConcat(lines, footer);
+ lines = pushOrConcat(lines, afterFooter);
+
+ return lines;
+ },
+
+ update: function(changed) {
+ var me = this;
+ var opts = me._options;
+
+ // Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
+ // that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
+ // which breaks any animations.
+ var existingModel = me._model;
+ var model = me._model = getBaseModel(opts);
+ var active = me._active;
+
+ var data = me._data;
+
+ // In the case where active.length === 0 we need to keep these at existing values for good animations
+ var alignment = {
+ xAlign: existingModel.xAlign,
+ yAlign: existingModel.yAlign
+ };
+ var backgroundPoint = {
+ x: existingModel.x,
+ y: existingModel.y
+ };
+ var tooltipSize = {
+ width: existingModel.width,
+ height: existingModel.height
+ };
+ var tooltipPosition = {
+ x: existingModel.caretX,
+ y: existingModel.caretY
+ };
+
+ var i, len;
+
+ if (active.length) {
+ model.opacity = 1;
+
+ var labelColors = [];
+ tooltipPosition = Chart.Tooltip.positioners[opts.position](active, me._eventPosition);
+
+ var tooltipItems = [];
+ for (i = 0, len = active.length; i < len; ++i) {
+ tooltipItems.push(createTooltipItem(active[i]));
+ }
+
+ // If the user provided a filter function, use it to modify the tooltip items
+ if (opts.filter) {
+ tooltipItems = tooltipItems.filter(function(a) {
+ return opts.filter(a, data);
+ });
+ }
+
+ // If the user provided a sorting function, use it to modify the tooltip items
+ if (opts.itemSort) {
+ tooltipItems = tooltipItems.sort(function(a, b) {
+ return opts.itemSort(a, b, data);
+ });
+ }
+
+ // Determine colors for boxes
+ helpers.each(tooltipItems, function(tooltipItem) {
+ labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
+ });
+
+ // Build the Text Lines
+ model.title = me.getTitle(tooltipItems, data);
+ model.beforeBody = me.getBeforeBody(tooltipItems, data);
+ model.body = me.getBody(tooltipItems, data);
+ model.afterBody = me.getAfterBody(tooltipItems, data);
+ model.footer = me.getFooter(tooltipItems, data);
+
+ // Initial positioning and colors
+ model.x = Math.round(tooltipPosition.x);
+ model.y = Math.round(tooltipPosition.y);
+ model.caretPadding = opts.caretPadding;
+ model.labelColors = labelColors;
+
+ // data points
+ model.dataPoints = tooltipItems;
+
+ // We need to determine alignment of the tooltip
+ tooltipSize = getTooltipSize(this, model);
+ alignment = determineAlignment(this, tooltipSize);
+ // Final Size and Position
+ backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment);
+ } else {
+ model.opacity = 0;
+ }
+
+ model.xAlign = alignment.xAlign;
+ model.yAlign = alignment.yAlign;
+ model.x = backgroundPoint.x;
+ model.y = backgroundPoint.y;
+ model.width = tooltipSize.width;
+ model.height = tooltipSize.height;
+
+ // Point where the caret on the tooltip points to
+ model.caretX = tooltipPosition.x;
+ model.caretY = tooltipPosition.y;
+
+ me._model = model;
+
+ if (changed && opts.custom) {
+ opts.custom.call(me, model);
+ }
+
+ return me;
+ },
+ drawCaret: function(tooltipPoint, size) {
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+ var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
+
+ ctx.lineTo(caretPosition.x1, caretPosition.y1);
+ ctx.lineTo(caretPosition.x2, caretPosition.y2);
+ ctx.lineTo(caretPosition.x3, caretPosition.y3);
+ },
+ getCaretPosition: function(tooltipPoint, size, vm) {
+ var x1, x2, x3;
+ var y1, y2, y3;
+ var caretSize = vm.caretSize;
+ var cornerRadius = vm.cornerRadius;
+ var xAlign = vm.xAlign,
+ yAlign = vm.yAlign;
+ var ptX = tooltipPoint.x,
+ ptY = tooltipPoint.y;
+ var width = size.width,
+ height = size.height;
+
+ if (yAlign === 'center') {
+ y2 = ptY + (height / 2);
+
+ if (xAlign === 'left') {
+ x1 = ptX;
+ x2 = x1 - caretSize;
+ x3 = x1;
+
+ y1 = y2 + caretSize;
+ y3 = y2 - caretSize;
+ } else {
+ x1 = ptX + width;
+ x2 = x1 + caretSize;
+ x3 = x1;
+
+ y1 = y2 - caretSize;
+ y3 = y2 + caretSize;
+ }
+ } else {
+ if (xAlign === 'left') {
+ x2 = ptX + cornerRadius + (caretSize);
+ x1 = x2 - caretSize;
+ x3 = x2 + caretSize;
+ } else if (xAlign === 'right') {
+ x2 = ptX + width - cornerRadius - caretSize;
+ x1 = x2 - caretSize;
+ x3 = x2 + caretSize;
+ } else {
+ x2 = ptX + (width / 2);
+ x1 = x2 - caretSize;
+ x3 = x2 + caretSize;
+ }
+ if (yAlign === 'top') {
+ y1 = ptY;
+ y2 = y1 - caretSize;
+ y3 = y1;
+ } else {
+ y1 = ptY + height;
+ y2 = y1 + caretSize;
+ y3 = y1;
+ // invert drawing order
+ var tmp = x3;
+ x3 = x1;
+ x1 = tmp;
+ }
+ }
+ return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
+ },
+ drawTitle: function(pt, vm, ctx, opacity) {
+ var title = vm.title;
+
+ if (title.length) {
+ ctx.textAlign = vm._titleAlign;
+ ctx.textBaseline = 'top';
+
+ var titleFontSize = vm.titleFontSize,
+ titleSpacing = vm.titleSpacing;
+
+ ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
+ ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+
+ var i, len;
+ for (i = 0, len = title.length; i < len; ++i) {
+ ctx.fillText(title[i], pt.x, pt.y);
+ pt.y += titleFontSize + titleSpacing; // Line Height and spacing
+
+ if (i + 1 === title.length) {
+ pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
+ }
+ }
+ }
+ },
+ drawBody: function(pt, vm, ctx, opacity) {
+ var bodyFontSize = vm.bodyFontSize;
+ var bodySpacing = vm.bodySpacing;
+ var body = vm.body;
+
+ ctx.textAlign = vm._bodyAlign;
+ ctx.textBaseline = 'top';
+
+ var textColor = mergeOpacity(vm.bodyFontColor, opacity);
+ ctx.fillStyle = textColor;
+ ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+
+ // Before Body
+ var xLinePadding = 0;
+ var fillLineOfText = function(line) {
+ ctx.fillText(line, pt.x + xLinePadding, pt.y);
+ pt.y += bodyFontSize + bodySpacing;
+ };
+
+ // Before body lines
+ helpers.each(vm.beforeBody, fillLineOfText);
+
+ var drawColorBoxes = vm.displayColors;
+ xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
+
+ // Draw body lines now
+ helpers.each(body, function(bodyItem, i) {
+ helpers.each(bodyItem.before, fillLineOfText);
+
+ helpers.each(bodyItem.lines, function(line) {
+ // Draw Legend-like boxes if needed
+ if (drawColorBoxes) {
+ // Fill a white rect so that colours merge nicely if the opacity is < 1
+ ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
+ ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
+
+ // Border
+ ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
+ ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
+
+ // Inner square
+ ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
+ ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
+
+ ctx.fillStyle = textColor;
+ }
+
+ fillLineOfText(line);
+ });
+
+ helpers.each(bodyItem.after, fillLineOfText);
+ });
+
+ // Reset back to 0 for after body
+ xLinePadding = 0;
+
+ // After body lines
+ helpers.each(vm.afterBody, fillLineOfText);
+ pt.y -= bodySpacing; // Remove last body spacing
+ },
+ drawFooter: function(pt, vm, ctx, opacity) {
+ var footer = vm.footer;
+
+ if (footer.length) {
+ pt.y += vm.footerMarginTop;
+
+ ctx.textAlign = vm._footerAlign;
+ ctx.textBaseline = 'top';
+
+ ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
+ ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
+
+ helpers.each(footer, function(line) {
+ ctx.fillText(line, pt.x, pt.y);
+ pt.y += vm.footerFontSize + vm.footerSpacing;
+ });
+ }
+ },
+ drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
+ ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
+ ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
+ ctx.lineWidth = vm.borderWidth;
+ var xAlign = vm.xAlign;
+ var yAlign = vm.yAlign;
+ var x = pt.x;
+ var y = pt.y;
+ var width = tooltipSize.width;
+ var height = tooltipSize.height;
+ var radius = vm.cornerRadius;
+
+ ctx.beginPath();
+ ctx.moveTo(x + radius, y);
+ if (yAlign === 'top') {
+ this.drawCaret(pt, tooltipSize);
+ }
+ ctx.lineTo(x + width - radius, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+ if (yAlign === 'center' && xAlign === 'right') {
+ this.drawCaret(pt, tooltipSize);
+ }
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+ if (yAlign === 'bottom') {
+ this.drawCaret(pt, tooltipSize);
+ }
+ ctx.lineTo(x + radius, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+ if (yAlign === 'center' && xAlign === 'left') {
+ this.drawCaret(pt, tooltipSize);
+ }
+ ctx.lineTo(x, y + radius);
+ ctx.quadraticCurveTo(x, y, x + radius, y);
+ ctx.closePath();
+
+ ctx.fill();
+
+ if (vm.borderWidth > 0) {
+ ctx.stroke();
+ }
+ },
+ draw: function() {
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+
+ if (vm.opacity === 0) {
+ return;
+ }
+
+ var tooltipSize = {
+ width: vm.width,
+ height: vm.height
+ };
+ var pt = {
+ x: vm.x,
+ y: vm.y
+ };
+
+ // IE11/Edge does not like very small opacities, so snap to 0
+ var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
+
+ // Truthy/falsey value for empty tooltip
+ var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
+
+ if (this._options.enabled && hasTooltipContent) {
+ // Draw Background
+ this.drawBackground(pt, vm, ctx, tooltipSize, opacity);
+
+ // Draw Title, Body, and Footer
+ pt.x += vm.xPadding;
+ pt.y += vm.yPadding;
+
+ // Titles
+ this.drawTitle(pt, vm, ctx, opacity);
+
+ // Body
+ this.drawBody(pt, vm, ctx, opacity);
+
+ // Footer
+ this.drawFooter(pt, vm, ctx, opacity);
+ }
+ },
+
+ /**
+ * Handle an event
+ * @private
+ * @param {IEvent} event - The event to handle
+ * @returns {Boolean} true if the tooltip changed
+ */
+ handleEvent: function(e) {
+ var me = this;
+ var options = me._options;
+ var changed = false;
+
+ me._lastActive = me._lastActive || [];
+
+ // Find Active Elements for tooltips
+ if (e.type === 'mouseout') {
+ me._active = [];
+ } else {
+ me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
+ }
+
+ // Remember Last Actives
+ changed = !helpers.arrayEquals(me._active, me._lastActive);
+
+ // If tooltip didn't change, do not handle the target event
+ if (!changed) {
+ return false;
+ }
+
+ me._lastActive = me._active;
+
+ if (options.enabled || options.custom) {
+ me._eventPosition = {
+ x: e.x,
+ y: e.y
+ };
+
+ var model = me._model;
+ me.update(true);
+ me.pivot();
+
+ // See if our tooltip position changed
+ changed |= (model.x !== me._model.x) || (model.y !== me._model.y);
+ }
+
+ return changed;
+ }
+ });
+
+ /**
+ * @namespace Chart.Tooltip.positioners
+ */
+ Chart.Tooltip.positioners = {
+ /**
+ * Average mode places the tooltip at the average position of the elements shown
+ * @function Chart.Tooltip.positioners.average
+ * @param elements {ChartElement[]} the elements being displayed in the tooltip
+ * @returns {Point} tooltip position
+ */
+ average: function(elements) {
+ if (!elements.length) {
+ return false;
+ }
+
+ var i, len;
+ var x = 0;
+ var y = 0;
+ var count = 0;
+
+ for (i = 0, len = elements.length; i < len; ++i) {
+ var el = elements[i];
+ if (el && el.hasValue()) {
+ var pos = el.tooltipPosition();
+ x += pos.x;
+ y += pos.y;
+ ++count;
+ }
+ }
+
+ return {
+ x: Math.round(x / count),
+ y: Math.round(y / count)
+ };
+ },
+
+ /**
+ * Gets the tooltip position nearest of the item nearest to the event position
+ * @function Chart.Tooltip.positioners.nearest
+ * @param elements {Chart.Element[]} the tooltip elements
+ * @param eventPosition {Point} the position of the event in canvas coordinates
+ * @returns {Point} the tooltip position
+ */
+ nearest: function(elements, eventPosition) {
+ var x = eventPosition.x;
+ var y = eventPosition.y;
+
+ var nearestElement;
+ var minDistance = Number.POSITIVE_INFINITY;
+ var i, len;
+ for (i = 0, len = elements.length; i < len; ++i) {
+ var el = elements[i];
+ if (el && el.hasValue()) {
+ var center = el.getCenterPoint();
+ var d = helpers.distanceBetweenPoints(eventPosition, center);
+
+ if (d < minDistance) {
+ minDistance = d;
+ nearestElement = el;
+ }
+ }
+ }
+
+ if (nearestElement) {
+ var tp = nearestElement.tooltipPosition();
+ x = tp.x;
+ y = tp.y;
+ }
+
+ return {
+ x: x,
+ y: y
+ };
+ }
+ };
+};
+
+},{}],35:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers,
+ globalOpts = Chart.defaults.global;
+
+ globalOpts.elements.arc = {
+ backgroundColor: globalOpts.defaultColor,
+ borderColor: '#fff',
+ borderWidth: 2
+ };
+
+ Chart.elements.Arc = Chart.Element.extend({
+ inLabelRange: function(mouseX) {
+ var vm = this._view;
+
+ if (vm) {
+ return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
+ }
+ return false;
+ },
+ inRange: function(chartX, chartY) {
+ var vm = this._view;
+
+ if (vm) {
+ var pointRelativePosition = helpers.getAngleFromPoint(vm, {
+ x: chartX,
+ y: chartY
+ }),
+ angle = pointRelativePosition.angle,
+ distance = pointRelativePosition.distance;
+
+ // Sanitise angle range
+ var startAngle = vm.startAngle;
+ var endAngle = vm.endAngle;
+ while (endAngle < startAngle) {
+ endAngle += 2.0 * Math.PI;
+ }
+ while (angle > endAngle) {
+ angle -= 2.0 * Math.PI;
+ }
+ while (angle < startAngle) {
+ angle += 2.0 * Math.PI;
+ }
+
+ // Check if within the range of the open/close angle
+ var betweenAngles = (angle >= startAngle && angle <= endAngle),
+ withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
+
+ return (betweenAngles && withinRadius);
+ }
+ return false;
+ },
+ getCenterPoint: function() {
+ var vm = this._view;
+ var halfAngle = (vm.startAngle + vm.endAngle) / 2;
+ var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
+ return {
+ x: vm.x + Math.cos(halfAngle) * halfRadius,
+ y: vm.y + Math.sin(halfAngle) * halfRadius
+ };
+ },
+ getArea: function() {
+ var vm = this._view;
+ return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+
+ var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
+ rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
+ return {
+ x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
+ y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
+ };
+ },
+ draw: function() {
+
+ var ctx = this._chart.ctx,
+ vm = this._view,
+ sA = vm.startAngle,
+ eA = vm.endAngle;
+
+ ctx.beginPath();
+
+ ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
+ ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
+
+ ctx.closePath();
+ ctx.strokeStyle = vm.borderColor;
+ ctx.lineWidth = vm.borderWidth;
+
+ ctx.fillStyle = vm.backgroundColor;
+
+ ctx.fill();
+ ctx.lineJoin = 'bevel';
+
+ if (vm.borderWidth) {
+ ctx.stroke();
+ }
+ }
+ });
+};
+
+},{}],36:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ var globalDefaults = Chart.defaults.global;
+
+ Chart.defaults.global.elements.line = {
+ tension: 0.4,
+ backgroundColor: globalDefaults.defaultColor,
+ borderWidth: 3,
+ borderColor: globalDefaults.defaultColor,
+ borderCapStyle: 'butt',
+ borderDash: [],
+ borderDashOffset: 0.0,
+ borderJoinStyle: 'miter',
+ capBezierPoints: true,
+ fill: true, // do we fill in the area between the line and its base axis
+ };
+
+ Chart.elements.Line = Chart.Element.extend({
+ draw: function() {
+ var me = this;
+ var vm = me._view;
+ var ctx = me._chart.ctx;
+ var spanGaps = vm.spanGaps;
+ var points = me._children.slice(); // clone array
+ var globalOptionLineElements = globalDefaults.elements.line;
+ var lastDrawnIndex = -1;
+ var index, current, previous, currentVM;
+
+ // If we are looping, adding the first point again
+ if (me._loop && points.length) {
+ points.push(points[0]);
+ }
+
+ ctx.save();
+
+ // Stroke Line Options
+ ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
+
+ // IE 9 and 10 do not support line dash
+ if (ctx.setLineDash) {
+ ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
+ }
+
+ ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
+ ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
+ ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
+ ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
+
+ // Stroke Line
+ ctx.beginPath();
+ lastDrawnIndex = -1;
+
+ for (index = 0; index < points.length; ++index) {
+ current = points[index];
+ previous = helpers.previousItem(points, index);
+ currentVM = current._view;
+
+ // First point moves to it's starting position no matter what
+ if (index === 0) {
+ if (!currentVM.skip) {
+ ctx.moveTo(currentVM.x, currentVM.y);
+ lastDrawnIndex = index;
+ }
+ } else {
+ previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
+
+ if (!currentVM.skip) {
+ if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
+ // There was a gap and this is the first point after the gap
+ ctx.moveTo(currentVM.x, currentVM.y);
+ } else {
+ // Line to next point
+ helpers.canvas.lineTo(ctx, previous._view, current._view);
+ }
+ lastDrawnIndex = index;
+ }
+ }
+ }
+
+ ctx.stroke();
+ ctx.restore();
+ }
+ });
+};
+
+},{}],37:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers,
+ globalOpts = Chart.defaults.global,
+ defaultColor = globalOpts.defaultColor;
+
+ globalOpts.elements.point = {
+ radius: 3,
+ pointStyle: 'circle',
+ backgroundColor: defaultColor,
+ borderWidth: 1,
+ borderColor: defaultColor,
+ // Hover
+ hitRadius: 1,
+ hoverRadius: 4,
+ hoverBorderWidth: 1
+ };
+
+ function xRange(mouseX) {
+ var vm = this._view;
+ return vm ? (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
+ }
+
+ function yRange(mouseY) {
+ var vm = this._view;
+ return vm ? (Math.pow(mouseY - vm.y, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
+ }
+
+ Chart.elements.Point = Chart.Element.extend({
+ inRange: function(mouseX, mouseY) {
+ var vm = this._view;
+ return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
+ },
+
+ inLabelRange: xRange,
+ inXRange: xRange,
+ inYRange: yRange,
+
+ getCenterPoint: function() {
+ var vm = this._view;
+ return {
+ x: vm.x,
+ y: vm.y
+ };
+ },
+ getArea: function() {
+ return Math.PI * Math.pow(this._view.radius, 2);
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+ return {
+ x: vm.x,
+ y: vm.y,
+ padding: vm.radius + vm.borderWidth
+ };
+ },
+ draw: function(chartArea) {
+ var vm = this._view;
+ var model = this._model;
+ var ctx = this._chart.ctx;
+ var pointStyle = vm.pointStyle;
+ var radius = vm.radius;
+ var x = vm.x;
+ var y = vm.y;
+ var color = Chart.helpers.color;
+ var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
+ var ratio = 0;
+
+ if (vm.skip) {
+ return;
+ }
+
+ ctx.strokeStyle = vm.borderColor || defaultColor;
+ ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth);
+ ctx.fillStyle = vm.backgroundColor || defaultColor;
+
+ // Cliping for Points.
+ // going out from inner charArea?
+ if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right*errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom*errMargin < model.y))) {
+ // Point fade out
+ if (model.x < chartArea.left) {
+ ratio = (x - model.x) / (chartArea.left - model.x);
+ } else if (chartArea.right*errMargin < model.x) {
+ ratio = (model.x - x) / (model.x - chartArea.right);
+ } else if (model.y < chartArea.top) {
+ ratio = (y - model.y) / (chartArea.top - model.y);
+ } else if (chartArea.bottom*errMargin < model.y) {
+ ratio = (model.y - y) / (model.y - chartArea.bottom);
+ }
+ ratio = Math.round(ratio*100) / 100;
+ ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
+ ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
+ }
+
+ Chart.canvasHelpers.drawPoint(ctx, pointStyle, radius, x, y);
+ }
+ });
+};
+
+},{}],38:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var globalOpts = Chart.defaults.global;
+
+ globalOpts.elements.rectangle = {
+ backgroundColor: globalOpts.defaultColor,
+ borderWidth: 0,
+ borderColor: globalOpts.defaultColor,
+ borderSkipped: 'bottom'
+ };
+
+ function isVertical(bar) {
+ return bar._view.width !== undefined;
+ }
+
+ /**
+ * Helper function to get the bounds of the bar regardless of the orientation
+ * @private
+ * @param bar {Chart.Element.Rectangle} the bar
+ * @return {Bounds} bounds of the bar
+ */
+ function getBarBounds(bar) {
+ var vm = bar._view;
+ var x1, x2, y1, y2;
+
+ if (isVertical(bar)) {
+ // vertical
+ var halfWidth = vm.width / 2;
+ x1 = vm.x - halfWidth;
+ x2 = vm.x + halfWidth;
+ y1 = Math.min(vm.y, vm.base);
+ y2 = Math.max(vm.y, vm.base);
+ } else {
+ // horizontal bar
+ var halfHeight = vm.height / 2;
+ x1 = Math.min(vm.x, vm.base);
+ x2 = Math.max(vm.x, vm.base);
+ y1 = vm.y - halfHeight;
+ y2 = vm.y + halfHeight;
+ }
+
+ return {
+ left: x1,
+ top: y1,
+ right: x2,
+ bottom: y2
+ };
+ }
+
+ Chart.elements.Rectangle = Chart.Element.extend({
+ draw: function() {
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+ var left, right, top, bottom, signX, signY, borderSkipped;
+ var borderWidth = vm.borderWidth;
+
+ if (!vm.horizontal) {
+ // bar
+ left = vm.x - vm.width / 2;
+ right = vm.x + vm.width / 2;
+ top = vm.y;
+ bottom = vm.base;
+ signX = 1;
+ signY = bottom > top? 1: -1;
+ borderSkipped = vm.borderSkipped || 'bottom';
+ } else {
+ // horizontal bar
+ left = vm.base;
+ right = vm.x;
+ top = vm.y - vm.height / 2;
+ bottom = vm.y + vm.height / 2;
+ signX = right > left? 1: -1;
+ signY = 1;
+ borderSkipped = vm.borderSkipped || 'left';
+ }
+
+ // Canvas doesn't allow us to stroke inside the width so we can
+ // adjust the sizes to fit if we're setting a stroke on the line
+ if (borderWidth) {
+ // borderWidth shold be less than bar width and bar height.
+ var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
+ borderWidth = borderWidth > barSize? barSize: borderWidth;
+ var halfStroke = borderWidth / 2;
+ // Adjust borderWidth when bar top position is near vm.base(zero).
+ var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
+ var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
+ var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
+ var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
+ // not become a vertical line?
+ if (borderLeft !== borderRight) {
+ top = borderTop;
+ bottom = borderBottom;
+ }
+ // not become a horizontal line?
+ if (borderTop !== borderBottom) {
+ left = borderLeft;
+ right = borderRight;
+ }
+ }
+
+ ctx.beginPath();
+ ctx.fillStyle = vm.backgroundColor;
+ ctx.strokeStyle = vm.borderColor;
+ ctx.lineWidth = borderWidth;
+
+ // Corner points, from bottom-left to bottom-right clockwise
+ // | 1 2 |
+ // | 0 3 |
+ var corners = [
+ [left, bottom],
+ [left, top],
+ [right, top],
+ [right, bottom]
+ ];
+
+ // Find first (starting) corner with fallback to 'bottom'
+ var borders = ['bottom', 'left', 'top', 'right'];
+ var startCorner = borders.indexOf(borderSkipped, 0);
+ if (startCorner === -1) {
+ startCorner = 0;
+ }
+
+ function cornerAt(index) {
+ return corners[(startCorner + index) % 4];
+ }
+
+ // Draw rectangle from 'startCorner'
+ var corner = cornerAt(0);
+ ctx.moveTo(corner[0], corner[1]);
+
+ for (var i = 1; i < 4; i++) {
+ corner = cornerAt(i);
+ ctx.lineTo(corner[0], corner[1]);
+ }
+
+ ctx.fill();
+ if (borderWidth) {
+ ctx.stroke();
+ }
+ },
+ height: function() {
+ var vm = this._view;
+ return vm.base - vm.y;
+ },
+ inRange: function(mouseX, mouseY) {
+ var inRange = false;
+
+ if (this._view) {
+ var bounds = getBarBounds(this);
+ inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
+ }
+
+ return inRange;
+ },
+ inLabelRange: function(mouseX, mouseY) {
+ var me = this;
+ if (!me._view) {
+ return false;
+ }
+
+ var inRange = false;
+ var bounds = getBarBounds(me);
+
+ if (isVertical(me)) {
+ inRange = mouseX >= bounds.left && mouseX <= bounds.right;
+ } else {
+ inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
+ }
+
+ return inRange;
+ },
+ inXRange: function(mouseX) {
+ var bounds = getBarBounds(this);
+ return mouseX >= bounds.left && mouseX <= bounds.right;
+ },
+ inYRange: function(mouseY) {
+ var bounds = getBarBounds(this);
+ return mouseY >= bounds.top && mouseY <= bounds.bottom;
+ },
+ getCenterPoint: function() {
+ var vm = this._view;
+ var x, y;
+ if (isVertical(this)) {
+ x = vm.x;
+ y = (vm.y + vm.base) / 2;
+ } else {
+ x = (vm.x + vm.base) / 2;
+ y = vm.y;
+ }
+
+ return {x: x, y: y};
+ },
+ getArea: function() {
+ var vm = this._view;
+ return vm.width * Math.abs(vm.y - vm.base);
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+ return {
+ x: vm.x,
+ y: vm.y
+ };
+ }
+ });
+
+};
+
+},{}],39:[function(require,module,exports){
+'use strict';
+
+// Chart.Platform implementation for targeting a web browser
+module.exports = function(Chart) {
+ var helpers = Chart.helpers;
+
+ // DOM event types -> Chart.js event types.
+ // Note: only events with different types are mapped.
+ // https://developer.mozilla.org/en-US/docs/Web/Events
+ var eventTypeMap = {
+ // Touch events
+ touchstart: 'mousedown',
+ touchmove: 'mousemove',
+ touchend: 'mouseup',
+
+ // Pointer events
+ pointerenter: 'mouseenter',
+ pointerdown: 'mousedown',
+ pointermove: 'mousemove',
+ pointerup: 'mouseup',
+ pointerleave: 'mouseout',
+ pointerout: 'mouseout'
+ };
+
+ /**
+ * The "used" size is the final value of a dimension property after all calculations have
+ * been performed. This method uses the computed style of `element` but returns undefined
+ * if the computed style is not expressed in pixels. That can happen in some cases where
+ * `element` has a size relative to its parent and this last one is not yet displayed,
+ * for example because of `display: none` on a parent node.
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
+ * @returns {Number} Size in pixels or undefined if unknown.
+ */
+ function readUsedSize(element, property) {
+ var value = helpers.getStyle(element, property);
+ var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
+ return matches? Number(matches[1]) : undefined;
+ }
+
+ /**
+ * Initializes the canvas style and render size without modifying the canvas display size,
+ * since responsiveness is handled by the controller.resize() method. The config is used
+ * to determine the aspect ratio to apply in case no explicit height has been specified.
+ */
+ function initCanvas(canvas, config) {
+ var style = canvas.style;
+
+ // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
+ // returns null or '' if no explicit value has been set to the canvas attribute.
+ var renderHeight = canvas.getAttribute('height');
+ var renderWidth = canvas.getAttribute('width');
+
+ // Chart.js modifies some canvas values that we want to restore on destroy
+ canvas._chartjs = {
+ initial: {
+ height: renderHeight,
+ width: renderWidth,
+ style: {
+ display: style.display,
+ height: style.height,
+ width: style.width
+ }
+ }
+ };
+
+ // Force canvas to display as block to avoid extra space caused by inline
+ // elements, which would interfere with the responsive resize process.
+ // https://github.com/chartjs/Chart.js/issues/2538
+ style.display = style.display || 'block';
+
+ if (renderWidth === null || renderWidth === '') {
+ var displayWidth = readUsedSize(canvas, 'width');
+ if (displayWidth !== undefined) {
+ canvas.width = displayWidth;
+ }
+ }
+
+ if (renderHeight === null || renderHeight === '') {
+ if (canvas.style.height === '') {
+ // If no explicit render height and style height, let's apply the aspect ratio,
+ // which one can be specified by the user but also by charts as default option
+ // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
+ canvas.height = canvas.width / (config.options.aspectRatio || 2);
+ } else {
+ var displayHeight = readUsedSize(canvas, 'height');
+ if (displayWidth !== undefined) {
+ canvas.height = displayHeight;
+ }
+ }
+ }
+
+ return canvas;
+ }
+
+ function createEvent(type, chart, x, y, nativeEvent) {
+ return {
+ type: type,
+ chart: chart,
+ native: nativeEvent || null,
+ x: x !== undefined? x : null,
+ y: y !== undefined? y : null,
+ };
+ }
+
+ function fromNativeEvent(event, chart) {
+ var type = eventTypeMap[event.type] || event.type;
+ var pos = helpers.getRelativePosition(event, chart);
+ return createEvent(type, chart, pos.x, pos.y, event);
+ }
+
+ function createResizer(handler) {
+ var iframe = document.createElement('iframe');
+ iframe.className = 'chartjs-hidden-iframe';
+ iframe.style.cssText =
+ 'display:block;'+
+ 'overflow:hidden;'+
+ 'border:0;'+
+ 'margin:0;'+
+ 'top:0;'+
+ 'left:0;'+
+ 'bottom:0;'+
+ 'right:0;'+
+ 'height:100%;'+
+ 'width:100%;'+
+ 'position:absolute;'+
+ 'pointer-events:none;'+
+ 'z-index:-1;';
+
+ // Prevent the iframe to gain focus on tab.
+ // https://github.com/chartjs/Chart.js/issues/3090
+ iframe.tabIndex = -1;
+
+ // If the iframe is re-attached to the DOM, the resize listener is removed because the
+ // content is reloaded, so make sure to install the handler after the iframe is loaded.
+ // https://github.com/chartjs/Chart.js/issues/3521
+ helpers.addEvent(iframe, 'load', function() {
+ helpers.addEvent(iframe.contentWindow || iframe, 'resize', handler);
+
+ // The iframe size might have changed while loading, which can also
+ // happen if the size has been changed while detached from the DOM.
+ handler();
+ });
+
+ return iframe;
+ }
+
+ function addResizeListener(node, listener, chart) {
+ var stub = node._chartjs = {
+ ticking: false
+ };
+
+ // Throttle the callback notification until the next animation frame.
+ var notify = function() {
+ if (!stub.ticking) {
+ stub.ticking = true;
+ helpers.requestAnimFrame.call(window, function() {
+ if (stub.resizer) {
+ stub.ticking = false;
+ return listener(createEvent('resize', chart));
+ }
+ });
+ }
+ };
+
+ // Let's keep track of this added iframe and thus avoid DOM query when removing it.
+ stub.resizer = createResizer(notify);
+
+ node.insertBefore(stub.resizer, node.firstChild);
+ }
+
+ function removeResizeListener(node) {
+ if (!node || !node._chartjs) {
+ return;
+ }
+
+ var resizer = node._chartjs.resizer;
+ if (resizer) {
+ resizer.parentNode.removeChild(resizer);
+ node._chartjs.resizer = null;
+ }
+
+ delete node._chartjs;
+ }
+
+ return {
+ acquireContext: function(item, config) {
+ if (typeof item === 'string') {
+ item = document.getElementById(item);
+ } else if (item.length) {
+ // Support for array based queries (such as jQuery)
+ item = item[0];
+ }
+
+ if (item && item.canvas) {
+ // Support for any object associated to a canvas (including a context2d)
+ item = item.canvas;
+ }
+
+ // To prevent canvas fingerprinting, some add-ons undefine the getContext
+ // method, for example: https://github.com/kkapsner/CanvasBlocker
+ // https://github.com/chartjs/Chart.js/issues/2807
+ var context = item && item.getContext && item.getContext('2d');
+
+ // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
+ // inside an iframe or when running in a protected environment. We could guess the
+ // types from their toString() value but let's keep things flexible and assume it's
+ // a sufficient condition if the item has a context2D which has item as `canvas`.
+ // https://github.com/chartjs/Chart.js/issues/3887
+ // https://github.com/chartjs/Chart.js/issues/4102
+ // https://github.com/chartjs/Chart.js/issues/4152
+ if (context && context.canvas === item) {
+ initCanvas(item, config);
+ return context;
+ }
+
+ return null;
+ },
+
+ releaseContext: function(context) {
+ var canvas = context.canvas;
+ if (!canvas._chartjs) {
+ return;
+ }
+
+ var initial = canvas._chartjs.initial;
+ ['height', 'width'].forEach(function(prop) {
+ var value = initial[prop];
+ if (value === undefined || value === null) {
+ canvas.removeAttribute(prop);
+ } else {
+ canvas.setAttribute(prop, value);
+ }
+ });
+
+ helpers.each(initial.style || {}, function(value, key) {
+ canvas.style[key] = value;
+ });
+
+ // The canvas render size might have been changed (and thus the state stack discarded),
+ // we can't use save() and restore() to restore the initial state. So make sure that at
+ // least the canvas context is reset to the default state by setting the canvas width.
+ // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
+ canvas.width = canvas.width;
+
+ delete canvas._chartjs;
+ },
+
+ addEventListener: function(chart, type, listener) {
+ var canvas = chart.canvas;
+ if (type === 'resize') {
+ // Note: the resize event is not supported on all browsers.
+ addResizeListener(canvas.parentNode, listener, chart);
+ return;
+ }
+
+ var stub = listener._chartjs || (listener._chartjs = {});
+ var proxies = stub.proxies || (stub.proxies = {});
+ var proxy = proxies[chart.id + '_' + type] = function(event) {
+ listener(fromNativeEvent(event, chart));
+ };
+
+ helpers.addEvent(canvas, type, proxy);
+ },
+
+ removeEventListener: function(chart, type, listener) {
+ var canvas = chart.canvas;
+ if (type === 'resize') {
+ // Note: the resize event is not supported on all browsers.
+ removeResizeListener(canvas.parentNode, listener);
+ return;
+ }
+
+ var stub = listener._chartjs || {};
+ var proxies = stub.proxies || {};
+ var proxy = proxies[chart.id + '_' + type];
+ if (!proxy) {
+ return;
+ }
+
+ helpers.removeEvent(canvas, type, proxy);
+ }
+ };
+};
+
+},{}],40:[function(require,module,exports){
+'use strict';
+
+// By default, select the browser (DOM) platform.
+// @TODO Make possible to select another platform at build time.
+var implementation = require(39);
+
+module.exports = function(Chart) {
+ /**
+ * @namespace Chart.platform
+ * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
+ * @since 2.4.0
+ */
+ Chart.platform = {
+ /**
+ * Called at chart construction time, returns a context2d instance implementing
+ * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
+ * @param {*} item - The native item from which to acquire context (platform specific)
+ * @param {Object} options - The chart options
+ * @returns {CanvasRenderingContext2D} context2d instance
+ */
+ acquireContext: function() {},
+
+ /**
+ * Called at chart destruction time, releases any resources associated to the context
+ * previously returned by the acquireContext() method.
+ * @param {CanvasRenderingContext2D} context - The context2d instance
+ * @returns {Boolean} true if the method succeeded, else false
+ */
+ releaseContext: function() {},
+
+ /**
+ * Registers the specified listener on the given chart.
+ * @param {Chart} chart - Chart from which to listen for event
+ * @param {String} type - The ({@link IEvent}) type to listen for
+ * @param {Function} listener - Receives a notification (an object that implements
+ * the {@link IEvent} interface) when an event of the specified type occurs.
+ */
+ addEventListener: function() {},
+
+ /**
+ * Removes the specified listener previously registered with addEventListener.
+ * @param {Chart} chart -Chart from which to remove the listener
+ * @param {String} type - The ({@link IEvent}) type to remove
+ * @param {Function} listener - The listener function to remove from the event target.
+ */
+ removeEventListener: function() {}
+ };
+
+ /**
+ * @interface IPlatform
+ * Allows abstracting platform dependencies away from the chart
+ * @borrows Chart.platform.acquireContext as acquireContext
+ * @borrows Chart.platform.releaseContext as releaseContext
+ * @borrows Chart.platform.addEventListener as addEventListener
+ * @borrows Chart.platform.removeEventListener as removeEventListener
+ */
+
+ /**
+ * @interface IEvent
+ * @prop {String} type - The event type name, possible values are:
+ * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
+ * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
+ * @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
+ * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
+ * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
+ */
+
+ Chart.helpers.extend(Chart.platform, implementation(Chart));
+};
+
+},{"39":39}],41:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+ /**
+ * Plugin based on discussion from the following Chart.js issues:
+ * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569
+ * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897
+ */
+ Chart.defaults.global.plugins.filler = {
+ propagate: true
+ };
+
+ var defaults = Chart.defaults;
+ var helpers = Chart.helpers;
+ var mappers = {
+ dataset: function(source) {
+ var index = source.fill;
+ var chart = source.chart;
+ var meta = chart.getDatasetMeta(index);
+ var visible = meta && chart.isDatasetVisible(index);
+ var points = (visible && meta.dataset._children) || [];
+
+ return !points.length? null : function(point, i) {
+ return points[i]._view || null;
+ };
+ },
+
+ boundary: function(source) {
+ var boundary = source.boundary;
+ var x = boundary? boundary.x : null;
+ var y = boundary? boundary.y : null;
+
+ return function(point) {
+ return {
+ x: x === null? point.x : x,
+ y: y === null? point.y : y,
+ };
+ };
+ }
+ };
+
+ // @todo if (fill[0] === '#')
+ function decodeFill(el, index, count) {
+ var model = el._model || {};
+ var fill = model.fill;
+ var target;
+
+ if (fill === undefined) {
+ fill = !!model.backgroundColor;
+ }
+
+ if (fill === false || fill === null) {
+ return false;
+ }
+
+ if (fill === true) {
+ return 'origin';
+ }
+
+ target = parseFloat(fill, 10);
+ if (isFinite(target) && Math.floor(target) === target) {
+ if (fill[0] === '-' || fill[0] === '+') {
+ target = index + target;
+ }
+
+ if (target === index || target < 0 || target >= count) {
+ return false;
+ }
+
+ return target;
+ }
+
+ switch (fill) {
+ // compatibility
+ case 'bottom':
+ return 'start';
+ case 'top':
+ return 'end';
+ case 'zero':
+ return 'origin';
+ // supported boundaries
+ case 'origin':
+ case 'start':
+ case 'end':
+ return fill;
+ // invalid fill values
+ default:
+ return false;
+ }
+ }
+
+ function computeBoundary(source) {
+ var model = source.el._model || {};
+ var scale = source.el._scale || {};
+ var fill = source.fill;
+ var target = null;
+ var horizontal;
+
+ if (isFinite(fill)) {
+ return null;
+ }
+
+ // Backward compatibility: until v3, we still need to support boundary values set on
+ // the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
+ // controllers might still use it (e.g. the Smith chart).
+
+ if (fill === 'start') {
+ target = model.scaleBottom === undefined? scale.bottom : model.scaleBottom;
+ } else if (fill === 'end') {
+ target = model.scaleTop === undefined? scale.top : model.scaleTop;
+ } else if (model.scaleZero !== undefined) {
+ target = model.scaleZero;
+ } else if (scale.getBasePosition) {
+ target = scale.getBasePosition();
+ } else if (scale.getBasePixel) {
+ target = scale.getBasePixel();
+ }
+
+ if (target !== undefined && target !== null) {
+ if (target.x !== undefined && target.y !== undefined) {
+ return target;
+ }
+
+ if (typeof target === 'number' && isFinite(target)) {
+ horizontal = scale.isHorizontal();
+ return {
+ x: horizontal? target : null,
+ y: horizontal? null : target
+ };
+ }
+ }
+
+ return null;
+ }
+
+ function resolveTarget(sources, index, propagate) {
+ var source = sources[index];
+ var fill = source.fill;
+ var visited = [index];
+ var target;
+
+ if (!propagate) {
+ return fill;
+ }
+
+ while (fill !== false && visited.indexOf(fill) === -1) {
+ if (!isFinite(fill)) {
+ return fill;
+ }
+
+ target = sources[fill];
+ if (!target) {
+ return false;
+ }
+
+ if (target.visible) {
+ return fill;
+ }
+
+ visited.push(fill);
+ fill = target.fill;
+ }
+
+ return false;
+ }
+
+ function createMapper(source) {
+ var fill = source.fill;
+ var type = 'dataset';
+
+ if (fill === false) {
+ return null;
+ }
+
+ if (!isFinite(fill)) {
+ type = 'boundary';
+ }
+
+ return mappers[type](source);
+ }
+
+ function isDrawable(point) {
+ return point && !point.skip;
+ }
+
+ function drawArea(ctx, curve0, curve1, len0, len1) {
+ var i;
+
+ if (!len0 || !len1) {
+ return;
+ }
+
+ // building first area curve (normal)
+ ctx.moveTo(curve0[0].x, curve0[0].y);
+ for (i=1; i0; --i) {
+ helpers.canvas.lineTo(ctx, curve1[i], curve1[i-1], true);
+ }
+ }
+
+ function doFill(ctx, points, mapper, view, color, loop) {
+ var count = points.length;
+ var span = view.spanGaps;
+ var curve0 = [];
+ var curve1 = [];
+ var len0 = 0;
+ var len1 = 0;
+ var i, ilen, index, p0, p1, d0, d1;
+
+ ctx.beginPath();
+
+ for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
+ index = i%count;
+ p0 = points[index]._view;
+ p1 = mapper(p0, index, view);
+ d0 = isDrawable(p0);
+ d1 = isDrawable(p1);
+
+ if (d0 && d1) {
+ len0 = curve0.push(p0);
+ len1 = curve1.push(p1);
+ } else if (len0 && len1) {
+ if (!span) {
+ drawArea(ctx, curve0, curve1, len0, len1);
+ len0 = len1 = 0;
+ curve0 = [];
+ curve1 = [];
+ } else {
+ if (d0) {
+ curve0.push(p0);
+ }
+ if (d1) {
+ curve1.push(p1);
+ }
+ }
+ }
+ }
+
+ drawArea(ctx, curve0, curve1, len0, len1);
+
+ ctx.closePath();
+ ctx.fillStyle = color;
+ ctx.fill();
+ }
+
+ return {
+ id: 'filler',
+
+ afterDatasetsUpdate: function(chart, options) {
+ var count = (chart.data.datasets || []).length;
+ var propagate = options.propagate;
+ var sources = [];
+ var meta, i, el, source;
+
+ for (i = 0; i < count; ++i) {
+ meta = chart.getDatasetMeta(i);
+ el = meta.dataset;
+ source = null;
+
+ if (el && el._model && el instanceof Chart.elements.Line) {
+ source = {
+ visible: chart.isDatasetVisible(i),
+ fill: decodeFill(el, i, count),
+ chart: chart,
+ el: el
+ };
+ }
+
+ meta.$filler = source;
+ sources.push(source);
+ }
+
+ for (i=0; i= me.width) {
+ totalHeight += fontSize + (labelOpts.padding);
+ lineWidths[lineWidths.length] = me.left;
+ }
+
+ // Store the hitbox width and height here. Final position will be updated in `draw`
+ hitboxes[i] = {
+ left: 0,
+ top: 0,
+ width: width,
+ height: fontSize
+ };
+
+ lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
+ });
+
+ minSize.height += totalHeight;
+
+ } else {
+ var vPadding = labelOpts.padding;
+ var columnWidths = me.columnWidths = [];
+ var totalWidth = labelOpts.padding;
+ var currentColWidth = 0;
+ var currentColHeight = 0;
+ var itemHeight = fontSize + vPadding;
+
+ helpers.each(me.legendItems, function(legendItem, i) {
+ var boxWidth = getBoxWidth(labelOpts, fontSize);
+ var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+
+ // If too tall, go to new column
+ if (currentColHeight + itemHeight > minSize.height) {
+ totalWidth += currentColWidth + labelOpts.padding;
+ columnWidths.push(currentColWidth); // previous column width
+
+ currentColWidth = 0;
+ currentColHeight = 0;
+ }
+
+ // Get max width
+ currentColWidth = Math.max(currentColWidth, itemWidth);
+ currentColHeight += itemHeight;
+
+ // Store the hitbox width and height here. Final position will be updated in `draw`
+ hitboxes[i] = {
+ left: 0,
+ top: 0,
+ width: itemWidth,
+ height: fontSize
+ };
+ });
+
+ totalWidth += currentColWidth;
+ columnWidths.push(currentColWidth);
+ minSize.width += totalWidth;
+ }
+ }
+
+ me.width = minSize.width;
+ me.height = minSize.height;
+ },
+ afterFit: noop,
+
+ // Shared Methods
+ isHorizontal: function() {
+ return this.options.position === 'top' || this.options.position === 'bottom';
+ },
+
+ // Actually draw the legend on the canvas
+ draw: function() {
+ var me = this;
+ var opts = me.options;
+ var labelOpts = opts.labels;
+ var globalDefault = Chart.defaults.global,
+ lineDefault = globalDefault.elements.line,
+ legendWidth = me.width,
+ lineWidths = me.lineWidths;
+
+ if (opts.display) {
+ var ctx = me.ctx,
+ cursor,
+ itemOrDefault = helpers.getValueOrDefault,
+ fontColor = itemOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor),
+ fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
+ fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
+ fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
+ labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
+
+ // Canvas setup
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'top';
+ ctx.lineWidth = 0.5;
+ ctx.strokeStyle = fontColor; // for strikethrough effect
+ ctx.fillStyle = fontColor; // render in correct colour
+ ctx.font = labelFont;
+
+ var boxWidth = getBoxWidth(labelOpts, fontSize),
+ hitboxes = me.legendHitBoxes;
+
+ // current position
+ var drawLegendBox = function(x, y, legendItem) {
+ if (isNaN(boxWidth) || boxWidth <= 0) {
+ return;
+ }
+
+ // Set the ctx for the box
+ ctx.save();
+
+ ctx.fillStyle = itemOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
+ ctx.lineCap = itemOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
+ ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
+ ctx.lineJoin = itemOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
+ ctx.lineWidth = itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
+ ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
+ var isLineWidthZero = (itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);
+
+ if (ctx.setLineDash) {
+ // IE 9 and 10 do not support line dash
+ ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash));
+ }
+
+ if (opts.labels && opts.labels.usePointStyle) {
+ // Recalculate x and y for drawPoint() because its expecting
+ // x and y to be center of figure (instead of top left)
+ var radius = fontSize * Math.SQRT2 / 2;
+ var offSet = radius / Math.SQRT2;
+ var centerX = x + offSet;
+ var centerY = y + offSet;
+
+ // Draw pointStyle as legend symbol
+ Chart.canvasHelpers.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
+ } else {
+ // Draw box as legend symbol
+ if (!isLineWidthZero) {
+ ctx.strokeRect(x, y, boxWidth, fontSize);
+ }
+ ctx.fillRect(x, y, boxWidth, fontSize);
+ }
+
+ ctx.restore();
+ };
+ var fillText = function(x, y, legendItem, textWidth) {
+ ctx.fillText(legendItem.text, boxWidth + (fontSize / 2) + x, y);
+
+ if (legendItem.hidden) {
+ // Strikethrough the text if hidden
+ ctx.beginPath();
+ ctx.lineWidth = 2;
+ ctx.moveTo(boxWidth + (fontSize / 2) + x, y + (fontSize / 2));
+ ctx.lineTo(boxWidth + (fontSize / 2) + x + textWidth, y + (fontSize / 2));
+ ctx.stroke();
+ }
+ };
+
+ // Horizontal
+ var isHorizontal = me.isHorizontal();
+ if (isHorizontal) {
+ cursor = {
+ x: me.left + ((legendWidth - lineWidths[0]) / 2),
+ y: me.top + labelOpts.padding,
+ line: 0
+ };
+ } else {
+ cursor = {
+ x: me.left + labelOpts.padding,
+ y: me.top + labelOpts.padding,
+ line: 0
+ };
+ }
+
+ var itemHeight = fontSize + labelOpts.padding;
+ helpers.each(me.legendItems, function(legendItem, i) {
+ var textWidth = ctx.measureText(legendItem.text).width,
+ width = boxWidth + (fontSize / 2) + textWidth,
+ x = cursor.x,
+ y = cursor.y;
+
+ if (isHorizontal) {
+ if (x + width >= legendWidth) {
+ y = cursor.y += itemHeight;
+ cursor.line++;
+ x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
+ }
+ } else if (y + itemHeight > me.bottom) {
+ x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
+ y = cursor.y = me.top + labelOpts.padding;
+ cursor.line++;
+ }
+
+ drawLegendBox(x, y, legendItem);
+
+ hitboxes[i].left = x;
+ hitboxes[i].top = y;
+
+ // Fill the actual label
+ fillText(x, y, legendItem, textWidth);
+
+ if (isHorizontal) {
+ cursor.x += width + (labelOpts.padding);
+ } else {
+ cursor.y += itemHeight;
+ }
+
+ });
+ }
+ },
+
+ /**
+ * Handle an event
+ * @private
+ * @param {IEvent} event - The event to handle
+ * @return {Boolean} true if a change occured
+ */
+ handleEvent: function(e) {
+ var me = this;
+ var opts = me.options;
+ var type = e.type === 'mouseup' ? 'click' : e.type;
+ var changed = false;
+
+ if (type === 'mousemove') {
+ if (!opts.onHover) {
+ return;
+ }
+ } else if (type === 'click') {
+ if (!opts.onClick) {
+ return;
+ }
+ } else {
+ return;
+ }
+
+ // Chart event already has relative position in it
+ var x = e.x,
+ y = e.y;
+
+ if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
+ // See if we are touching one of the dataset boxes
+ var lh = me.legendHitBoxes;
+ for (var i = 0; i < lh.length; ++i) {
+ var hitBox = lh[i];
+
+ if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
+ // Touching an element
+ if (type === 'click') {
+ // use e.native for backwards compatibility
+ opts.onClick.call(me, e.native, me.legendItems[i]);
+ changed = true;
+ break;
+ } else if (type === 'mousemove') {
+ // use e.native for backwards compatibility
+ opts.onHover.call(me, e.native, me.legendItems[i]);
+ changed = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return changed;
+ }
+ });
+
+ function createNewLegendAndAttach(chart, legendOpts) {
+ var legend = new Chart.Legend({
+ ctx: chart.ctx,
+ options: legendOpts,
+ chart: chart
+ });
+
+ layout.configure(chart, legend, legendOpts);
+ layout.addBox(chart, legend);
+ chart.legend = legend;
+ }
+
+ return {
+ id: 'legend',
+
+ beforeInit: function(chart) {
+ var legendOpts = chart.options.legend;
+
+ if (legendOpts) {
+ createNewLegendAndAttach(chart, legendOpts);
+ }
+ },
+
+ beforeUpdate: function(chart) {
+ var legendOpts = chart.options.legend;
+ var legend = chart.legend;
+
+ if (legendOpts) {
+ legendOpts = helpers.configMerge(Chart.defaults.global.legend, legendOpts);
+
+ if (legend) {
+ layout.configure(chart, legend, legendOpts);
+ legend.options = legendOpts;
+ } else {
+ createNewLegendAndAttach(chart, legendOpts);
+ }
+ } else if (legend) {
+ layout.removeBox(chart, legend);
+ delete chart.legend;
+ }
+ },
+
+ afterEvent: function(chart, e) {
+ var legend = chart.legend;
+ if (legend) {
+ legend.handleEvent(e);
+ }
+ }
+ };
+};
+
+},{}],43:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ var layout = Chart.layoutService;
+ var noop = helpers.noop;
+
+ Chart.defaults.global.title = {
+ display: false,
+ position: 'top',
+ fullWidth: true,
+ weight: 2000, // by default greater than legend (1000) to be above
+ fontStyle: 'bold',
+ padding: 10,
+
+ // actual title
+ text: ''
+ };
+
+ Chart.Title = Chart.Element.extend({
+ initialize: function(config) {
+ var me = this;
+ helpers.extend(me, config);
+
+ // Contains hit boxes for each dataset (in dataset order)
+ me.legendHitBoxes = [];
+ },
+
+ // These methods are ordered by lifecycle. Utilities then follow.
+
+ beforeUpdate: noop,
+ update: function(maxWidth, maxHeight, margins) {
+ var me = this;
+
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+ me.beforeUpdate();
+
+ // Absorb the master measurements
+ me.maxWidth = maxWidth;
+ me.maxHeight = maxHeight;
+ me.margins = margins;
+
+ // Dimensions
+ me.beforeSetDimensions();
+ me.setDimensions();
+ me.afterSetDimensions();
+ // Labels
+ me.beforeBuildLabels();
+ me.buildLabels();
+ me.afterBuildLabels();
+
+ // Fit
+ me.beforeFit();
+ me.fit();
+ me.afterFit();
+ //
+ me.afterUpdate();
+
+ return me.minSize;
+
+ },
+ afterUpdate: noop,
+
+ //
+
+ beforeSetDimensions: noop,
+ setDimensions: function() {
+ var me = this;
+ // Set the unconstrained dimension before label rotation
+ if (me.isHorizontal()) {
+ // Reset position before calculating rotation
+ me.width = me.maxWidth;
+ me.left = 0;
+ me.right = me.width;
+ } else {
+ me.height = me.maxHeight;
+
+ // Reset position before calculating rotation
+ me.top = 0;
+ me.bottom = me.height;
+ }
+
+ // Reset padding
+ me.paddingLeft = 0;
+ me.paddingTop = 0;
+ me.paddingRight = 0;
+ me.paddingBottom = 0;
+
+ // Reset minSize
+ me.minSize = {
+ width: 0,
+ height: 0
+ };
+ },
+ afterSetDimensions: noop,
+
+ //
+
+ beforeBuildLabels: noop,
+ buildLabels: noop,
+ afterBuildLabels: noop,
+
+ //
+
+ beforeFit: noop,
+ fit: function() {
+ var me = this,
+ valueOrDefault = helpers.getValueOrDefault,
+ opts = me.options,
+ globalDefaults = Chart.defaults.global,
+ display = opts.display,
+ fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
+ minSize = me.minSize;
+
+ if (me.isHorizontal()) {
+ minSize.width = me.maxWidth; // fill all the width
+ minSize.height = display ? fontSize + (opts.padding * 2) : 0;
+ } else {
+ minSize.width = display ? fontSize + (opts.padding * 2) : 0;
+ minSize.height = me.maxHeight; // fill all the height
+ }
+
+ me.width = minSize.width;
+ me.height = minSize.height;
+
+ },
+ afterFit: noop,
+
+ // Shared Methods
+ isHorizontal: function() {
+ var pos = this.options.position;
+ return pos === 'top' || pos === 'bottom';
+ },
+
+ // Actually draw the title block on the canvas
+ draw: function() {
+ var me = this,
+ ctx = me.ctx,
+ valueOrDefault = helpers.getValueOrDefault,
+ opts = me.options,
+ globalDefaults = Chart.defaults.global;
+
+ if (opts.display) {
+ var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
+ fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle),
+ fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily),
+ titleFont = helpers.fontString(fontSize, fontStyle, fontFamily),
+ rotation = 0,
+ titleX,
+ titleY,
+ top = me.top,
+ left = me.left,
+ bottom = me.bottom,
+ right = me.right,
+ maxWidth;
+
+ ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
+ ctx.font = titleFont;
+
+ // Horizontal
+ if (me.isHorizontal()) {
+ titleX = left + ((right - left) / 2); // midpoint of the width
+ titleY = top + ((bottom - top) / 2); // midpoint of the height
+ maxWidth = right - left;
+ } else {
+ titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2);
+ titleY = top + ((bottom - top) / 2);
+ maxWidth = bottom - top;
+ rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
+ }
+
+ ctx.save();
+ ctx.translate(titleX, titleY);
+ ctx.rotate(rotation);
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillText(opts.text, 0, 0, maxWidth);
+ ctx.restore();
+ }
+ }
+ });
+
+ function createNewTitleBlockAndAttach(chart, titleOpts) {
+ var title = new Chart.Title({
+ ctx: chart.ctx,
+ options: titleOpts,
+ chart: chart
+ });
+
+ layout.configure(chart, title, titleOpts);
+ layout.addBox(chart, title);
+ chart.titleBlock = title;
+ }
+
+ return {
+ id: 'title',
+
+ beforeInit: function(chart) {
+ var titleOpts = chart.options.title;
+
+ if (titleOpts) {
+ createNewTitleBlockAndAttach(chart, titleOpts);
+ }
+ },
+
+ beforeUpdate: function(chart) {
+ var titleOpts = chart.options.title;
+ var titleBlock = chart.titleBlock;
+
+ if (titleOpts) {
+ titleOpts = helpers.configMerge(Chart.defaults.global.title, titleOpts);
+
+ if (titleBlock) {
+ layout.configure(chart, titleBlock, titleOpts);
+ titleBlock.options = titleOpts;
+ } else {
+ createNewTitleBlockAndAttach(chart, titleOpts);
+ }
+ } else if (titleBlock) {
+ Chart.layoutService.removeBox(chart, titleBlock);
+ delete chart.titleBlock;
+ }
+ }
+ };
+};
+
+},{}],44:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ // Default config for a category scale
+ var defaultConfig = {
+ position: 'bottom'
+ };
+
+ var DatasetScale = Chart.Scale.extend({
+ /**
+ * Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
+ * else fall back to data.labels
+ * @private
+ */
+ getLabels: function() {
+ var data = this.chart.data;
+ return (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
+ },
+
+ determineDataLimits: function() {
+ var me = this;
+ var labels = me.getLabels();
+ me.minIndex = 0;
+ me.maxIndex = labels.length - 1;
+ var findIndex;
+
+ if (me.options.ticks.min !== undefined) {
+ // user specified min value
+ findIndex = helpers.indexOf(labels, me.options.ticks.min);
+ me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
+ }
+
+ if (me.options.ticks.max !== undefined) {
+ // user specified max value
+ findIndex = helpers.indexOf(labels, me.options.ticks.max);
+ me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
+ }
+
+ me.min = labels[me.minIndex];
+ me.max = labels[me.maxIndex];
+ },
+
+ buildTicks: function() {
+ var me = this;
+ var labels = me.getLabels();
+ // If we are viewing some subset of labels, slice the original array
+ me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
+ },
+
+ getLabelForIndex: function(index, datasetIndex) {
+ var me = this;
+ var data = me.chart.data;
+ var isHorizontal = me.isHorizontal();
+
+ if (data.yLabels && !isHorizontal) {
+ return me.getRightValue(data.datasets[datasetIndex].data[index]);
+ }
+ return me.ticks[index - me.minIndex];
+ },
+
+ // Used to get data value locations. Value can either be an index or a numerical value
+ getPixelForValue: function(value, index, datasetIndex, includeOffset) {
+ var me = this;
+ // 1 is added because we need the length but we have the indexes
+ var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+
+ // If value is a data object, then index is the index in the data array,
+ // not the index of the scale. We need to change that.
+ var valueCategory;
+ if (value !== undefined && value !== null) {
+ valueCategory = me.isHorizontal() ? value.x : value.y;
+ }
+ if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
+ var labels = me.getLabels();
+ value = valueCategory || value;
+ var idx = labels.indexOf(value);
+ index = idx !== -1 ? idx : index;
+ }
+
+ if (me.isHorizontal()) {
+ var valueWidth = me.width / offsetAmt;
+ var widthOffset = (valueWidth * (index - me.minIndex));
+
+ if (me.options.gridLines.offsetGridLines && includeOffset || me.maxIndex === me.minIndex && includeOffset) {
+ widthOffset += (valueWidth / 2);
+ }
+
+ return me.left + Math.round(widthOffset);
+ }
+ var valueHeight = me.height / offsetAmt;
+ var heightOffset = (valueHeight * (index - me.minIndex));
+
+ if (me.options.gridLines.offsetGridLines && includeOffset) {
+ heightOffset += (valueHeight / 2);
+ }
+
+ return me.top + Math.round(heightOffset);
+ },
+ getPixelForTick: function(index, includeOffset) {
+ return this.getPixelForValue(this.ticks[index], index + this.minIndex, null, includeOffset);
+ },
+ getValueForPixel: function(pixel) {
+ var me = this;
+ var value;
+ var offsetAmt = Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+ var horz = me.isHorizontal();
+ var valueDimension = (horz ? me.width : me.height) / offsetAmt;
+
+ pixel -= horz ? me.left : me.top;
+
+ if (me.options.gridLines.offsetGridLines) {
+ pixel -= (valueDimension / 2);
+ }
+
+ if (pixel <= 0) {
+ value = 0;
+ } else {
+ value = Math.round(pixel / valueDimension);
+ }
+
+ return value;
+ },
+ getBasePixel: function() {
+ return this.bottom;
+ }
+ });
+
+ Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig);
+
+};
+
+},{}],45:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ var defaultConfig = {
+ position: 'left',
+ ticks: {
+ callback: Chart.Ticks.formatters.linear
+ }
+ };
+
+ var LinearScale = Chart.LinearScaleBase.extend({
+
+ determineDataLimits: function() {
+ var me = this;
+ var opts = me.options;
+ var chart = me.chart;
+ var data = chart.data;
+ var datasets = data.datasets;
+ var isHorizontal = me.isHorizontal();
+ var DEFAULT_MIN = 0;
+ var DEFAULT_MAX = 1;
+
+ function IDMatches(meta) {
+ return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+ }
+
+ // First Calculate the range
+ me.min = null;
+ me.max = null;
+
+ var hasStacks = opts.stacked;
+ if (hasStacks === undefined) {
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ if (hasStacks) {
+ return;
+ }
+
+ var meta = chart.getDatasetMeta(datasetIndex);
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+ meta.stack !== undefined) {
+ hasStacks = true;
+ }
+ });
+ }
+
+ if (opts.stacked || hasStacks) {
+ var valuesPerStack = {};
+
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+ var key = [
+ meta.type,
+ // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+ ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+ meta.stack
+ ].join('.');
+
+ if (valuesPerStack[key] === undefined) {
+ valuesPerStack[key] = {
+ positiveValues: [],
+ negativeValues: []
+ };
+ }
+
+ // Store these per type
+ var positiveValues = valuesPerStack[key].positiveValues;
+ var negativeValues = valuesPerStack[key].negativeValues;
+
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ positiveValues[index] = positiveValues[index] || 0;
+ negativeValues[index] = negativeValues[index] || 0;
+
+ if (opts.relativePoints) {
+ positiveValues[index] = 100;
+ } else if (value < 0) {
+ negativeValues[index] += value;
+ } else {
+ positiveValues[index] += value;
+ }
+ });
+ }
+ });
+
+ helpers.each(valuesPerStack, function(valuesForType) {
+ var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
+ var minVal = helpers.min(values);
+ var maxVal = helpers.max(values);
+ me.min = me.min === null ? minVal : Math.min(me.min, minVal);
+ me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
+ });
+
+ } else {
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ if (me.min === null) {
+ me.min = value;
+ } else if (value < me.min) {
+ me.min = value;
+ }
+
+ if (me.max === null) {
+ me.max = value;
+ } else if (value > me.max) {
+ me.max = value;
+ }
+ });
+ }
+ });
+ }
+
+ me.min = isFinite(me.min) ? me.min : DEFAULT_MIN;
+ me.max = isFinite(me.max) ? me.max : DEFAULT_MAX;
+
+ // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
+ this.handleTickRangeOptions();
+ },
+ getTickLimit: function() {
+ var maxTicks;
+ var me = this;
+ var tickOpts = me.options.ticks;
+
+ if (me.isHorizontal()) {
+ maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
+ } else {
+ // The factor of 2 used to scale the font size has been experimentally determined.
+ var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize);
+ maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
+ }
+
+ return maxTicks;
+ },
+ // Called after the ticks are built. We need
+ handleDirectionalChanges: function() {
+ if (!this.isHorizontal()) {
+ // We are in a vertical orientation. The top value is the highest. So reverse the array
+ this.ticks.reverse();
+ }
+ },
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+ // Utils
+ getPixelForValue: function(value) {
+ // This must be called after fit has been run so that
+ // this.left, this.top, this.right, and this.bottom have been defined
+ var me = this;
+ var start = me.start;
+
+ var rightValue = +me.getRightValue(value);
+ var pixel;
+ var range = me.end - start;
+
+ if (me.isHorizontal()) {
+ pixel = me.left + (me.width / range * (rightValue - start));
+ return Math.round(pixel);
+ }
+
+ pixel = me.bottom - (me.height / range * (rightValue - start));
+ return Math.round(pixel);
+ },
+ getValueForPixel: function(pixel) {
+ var me = this;
+ var isHorizontal = me.isHorizontal();
+ var innerDimension = isHorizontal ? me.width : me.height;
+ var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
+ return me.start + ((me.end - me.start) * offset);
+ },
+ getPixelForTick: function(index) {
+ return this.getPixelForValue(this.ticksAsNumbers[index]);
+ }
+ });
+ Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig);
+
+};
+
+},{}],46:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers,
+ noop = helpers.noop;
+
+ Chart.LinearScaleBase = Chart.Scale.extend({
+ handleTickRangeOptions: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+
+ // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
+ // do nothing since that would make the chart weird. If the user really wants a weird chart
+ // axis, they can manually override it
+ if (tickOpts.beginAtZero) {
+ var minSign = helpers.sign(me.min);
+ var maxSign = helpers.sign(me.max);
+
+ if (minSign < 0 && maxSign < 0) {
+ // move the top up to 0
+ me.max = 0;
+ } else if (minSign > 0 && maxSign > 0) {
+ // move the bottom down to 0
+ me.min = 0;
+ }
+ }
+
+ if (tickOpts.min !== undefined) {
+ me.min = tickOpts.min;
+ } else if (tickOpts.suggestedMin !== undefined) {
+ if (me.min === null) {
+ me.min = tickOpts.suggestedMin;
+ } else {
+ me.min = Math.min(me.min, tickOpts.suggestedMin);
+ }
+ }
+
+ if (tickOpts.max !== undefined) {
+ me.max = tickOpts.max;
+ } else if (tickOpts.suggestedMax !== undefined) {
+ if (me.max === null) {
+ me.max = tickOpts.suggestedMax;
+ } else {
+ me.max = Math.max(me.max, tickOpts.suggestedMax);
+ }
+ }
+
+ if (me.min === me.max) {
+ me.max++;
+
+ if (!tickOpts.beginAtZero) {
+ me.min--;
+ }
+ }
+ },
+ getTickLimit: noop,
+ handleDirectionalChanges: noop,
+
+ buildTicks: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+
+ // Figure out what the max number of ticks we can support it is based on the size of
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+ // the graph. Make sure we always have at least 2 ticks
+ var maxTicks = me.getTickLimit();
+ maxTicks = Math.max(2, maxTicks);
+
+ var numericGeneratorOptions = {
+ maxTicks: maxTicks,
+ min: tickOpts.min,
+ max: tickOpts.max,
+ stepSize: helpers.getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
+ };
+ var ticks = me.ticks = Chart.Ticks.generators.linear(numericGeneratorOptions, me);
+
+ me.handleDirectionalChanges();
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ me.max = helpers.max(ticks);
+ me.min = helpers.min(ticks);
+
+ if (tickOpts.reverse) {
+ ticks.reverse();
+
+ me.start = me.max;
+ me.end = me.min;
+ } else {
+ me.start = me.min;
+ me.end = me.max;
+ }
+ },
+ convertTicksToLabels: function() {
+ var me = this;
+ me.ticksAsNumbers = me.ticks.slice();
+ me.zeroLineIndex = me.ticks.indexOf(0);
+
+ Chart.Scale.prototype.convertTicksToLabels.call(me);
+ }
+ });
+};
+
+},{}],47:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+
+ var defaultConfig = {
+ position: 'left',
+
+ // label settings
+ ticks: {
+ callback: Chart.Ticks.formatters.logarithmic
+ }
+ };
+
+ var LogarithmicScale = Chart.Scale.extend({
+ determineDataLimits: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+ var chart = me.chart;
+ var data = chart.data;
+ var datasets = data.datasets;
+ var getValueOrDefault = helpers.getValueOrDefault;
+ var isHorizontal = me.isHorizontal();
+ function IDMatches(meta) {
+ return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
+ }
+
+ // Calculate Range
+ me.min = null;
+ me.max = null;
+ me.minNotZero = null;
+
+ var hasStacks = opts.stacked;
+ if (hasStacks === undefined) {
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ if (hasStacks) {
+ return;
+ }
+
+ var meta = chart.getDatasetMeta(datasetIndex);
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+ meta.stack !== undefined) {
+ hasStacks = true;
+ }
+ });
+ }
+
+ if (opts.stacked || hasStacks) {
+ var valuesPerStack = {};
+
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+ var key = [
+ meta.type,
+ // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+ ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+ meta.stack
+ ].join('.');
+
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+ if (valuesPerStack[key] === undefined) {
+ valuesPerStack[key] = [];
+ }
+
+ helpers.each(dataset.data, function(rawValue, index) {
+ var values = valuesPerStack[key];
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ values[index] = values[index] || 0;
+
+ if (opts.relativePoints) {
+ values[index] = 100;
+ } else {
+ // Don't need to split positive and negative since the log scale can't handle a 0 crossing
+ values[index] += value;
+ }
+ });
+ }
+ });
+
+ helpers.each(valuesPerStack, function(valuesForType) {
+ var minVal = helpers.min(valuesForType);
+ var maxVal = helpers.max(valuesForType);
+ me.min = me.min === null ? minVal : Math.min(me.min, minVal);
+ me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
+ });
+
+ } else {
+ helpers.each(datasets, function(dataset, datasetIndex) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ if (me.min === null) {
+ me.min = value;
+ } else if (value < me.min) {
+ me.min = value;
+ }
+
+ if (me.max === null) {
+ me.max = value;
+ } else if (value > me.max) {
+ me.max = value;
+ }
+
+ if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
+ me.minNotZero = value;
+ }
+ });
+ }
+ });
+ }
+
+ me.min = getValueOrDefault(tickOpts.min, me.min);
+ me.max = getValueOrDefault(tickOpts.max, me.max);
+
+ if (me.min === me.max) {
+ if (me.min !== 0 && me.min !== null) {
+ me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
+ me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
+ } else {
+ me.min = 1;
+ me.max = 10;
+ }
+ }
+ },
+ buildTicks: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+
+ var generationOptions = {
+ min: tickOpts.min,
+ max: tickOpts.max
+ };
+ var ticks = me.ticks = Chart.Ticks.generators.logarithmic(generationOptions, me);
+
+ if (!me.isHorizontal()) {
+ // We are in a vertical orientation. The top value is the highest. So reverse the array
+ ticks.reverse();
+ }
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ me.max = helpers.max(ticks);
+ me.min = helpers.min(ticks);
+
+ if (tickOpts.reverse) {
+ ticks.reverse();
+
+ me.start = me.max;
+ me.end = me.min;
+ } else {
+ me.start = me.min;
+ me.end = me.max;
+ }
+ },
+ convertTicksToLabels: function() {
+ this.tickValues = this.ticks.slice();
+
+ Chart.Scale.prototype.convertTicksToLabels.call(this);
+ },
+ // Get the correct tooltip label
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+ getPixelForTick: function(index) {
+ return this.getPixelForValue(this.tickValues[index]);
+ },
+ getPixelForValue: function(value) {
+ var me = this;
+ var innerDimension;
+ var pixel;
+
+ var start = me.start;
+ var newVal = +me.getRightValue(value);
+ var range;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+
+ if (me.isHorizontal()) {
+ range = helpers.log10(me.end) - helpers.log10(start); // todo: if start === 0
+ if (newVal === 0) {
+ pixel = me.left;
+ } else {
+ innerDimension = me.width;
+ pixel = me.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
+ }
+ } else {
+ // Bottom - top since pixels increase downward on a screen
+ innerDimension = me.height;
+ if (start === 0 && !tickOpts.reverse) {
+ range = helpers.log10(me.end) - helpers.log10(me.minNotZero);
+ if (newVal === start) {
+ pixel = me.bottom;
+ } else if (newVal === me.minNotZero) {
+ pixel = me.bottom - innerDimension * 0.02;
+ } else {
+ pixel = me.bottom - innerDimension * 0.02 - (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
+ }
+ } else if (me.end === 0 && tickOpts.reverse) {
+ range = helpers.log10(me.start) - helpers.log10(me.minNotZero);
+ if (newVal === me.end) {
+ pixel = me.top;
+ } else if (newVal === me.minNotZero) {
+ pixel = me.top + innerDimension * 0.02;
+ } else {
+ pixel = me.top + innerDimension * 0.02 + (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
+ }
+ } else if (newVal === 0) {
+ pixel = tickOpts.reverse ? me.top : me.bottom;
+ } else {
+ range = helpers.log10(me.end) - helpers.log10(start);
+ innerDimension = me.height;
+ pixel = me.bottom - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
+ }
+ }
+ return pixel;
+ },
+ getValueForPixel: function(pixel) {
+ var me = this;
+ var range = helpers.log10(me.end) - helpers.log10(me.start);
+ var value, innerDimension;
+
+ if (me.isHorizontal()) {
+ innerDimension = me.width;
+ value = me.start * Math.pow(10, (pixel - me.left) * range / innerDimension);
+ } else { // todo: if start === 0
+ innerDimension = me.height;
+ value = Math.pow(10, (me.bottom - pixel) * range / innerDimension) / me.start;
+ }
+ return value;
+ }
+ });
+ Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);
+
+};
+
+},{}],48:[function(require,module,exports){
+'use strict';
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ var globalDefaults = Chart.defaults.global;
+
+ var defaultConfig = {
+ display: true,
+
+ // Boolean - Whether to animate scaling the chart from the centre
+ animate: true,
+ position: 'chartArea',
+
+ angleLines: {
+ display: true,
+ color: 'rgba(0, 0, 0, 0.1)',
+ lineWidth: 1
+ },
+
+ gridLines: {
+ circular: false
+ },
+
+ // label settings
+ ticks: {
+ // Boolean - Show a backdrop to the scale label
+ showLabelBackdrop: true,
+
+ // String - The colour of the label backdrop
+ backdropColor: 'rgba(255,255,255,0.75)',
+
+ // Number - The backdrop padding above & below the label in pixels
+ backdropPaddingY: 2,
+
+ // Number - The backdrop padding to the side of the label in pixels
+ backdropPaddingX: 2,
+
+ callback: Chart.Ticks.formatters.linear
+ },
+
+ pointLabels: {
+ // Boolean - if true, show point labels
+ display: true,
+
+ // Number - Point label font size in pixels
+ fontSize: 10,
+
+ // Function - Used to convert point labels
+ callback: function(label) {
+ return label;
+ }
+ }
+ };
+
+ function getValueCount(scale) {
+ var opts = scale.options;
+ return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
+ }
+
+ function getPointLabelFontOptions(scale) {
+ var pointLabelOptions = scale.options.pointLabels;
+ var fontSize = helpers.getValueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
+ var fontStyle = helpers.getValueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
+ var fontFamily = helpers.getValueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
+ var font = helpers.fontString(fontSize, fontStyle, fontFamily);
+
+ return {
+ size: fontSize,
+ style: fontStyle,
+ family: fontFamily,
+ font: font
+ };
+ }
+
+ function measureLabelSize(ctx, fontSize, label) {
+ if (helpers.isArray(label)) {
+ return {
+ w: helpers.longestText(ctx, ctx.font, label),
+ h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
+ };
+ }
+
+ return {
+ w: ctx.measureText(label).width,
+ h: fontSize
+ };
+ }
+
+ function determineLimits(angle, pos, size, min, max) {
+ if (angle === min || angle === max) {
+ return {
+ start: pos - (size / 2),
+ end: pos + (size / 2)
+ };
+ } else if (angle < min || angle > max) {
+ return {
+ start: pos - size - 5,
+ end: pos
+ };
+ }
+
+ return {
+ start: pos,
+ end: pos + size + 5
+ };
+ }
+
+ /**
+ * Helper function to fit a radial linear scale with point labels
+ */
+ function fitWithPointLabels(scale) {
+ /*
+ * Right, this is really confusing and there is a lot of maths going on here
+ * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
+ *
+ * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
+ *
+ * Solution:
+ *
+ * We assume the radius of the polygon is half the size of the canvas at first
+ * at each index we check if the text overlaps.
+ *
+ * Where it does, we store that angle and that index.
+ *
+ * After finding the largest index and angle we calculate how much we need to remove
+ * from the shape radius to move the point inwards by that x.
+ *
+ * We average the left and right distances to get the maximum shape radius that can fit in the box
+ * along with labels.
+ *
+ * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
+ * on each side, removing that from the size, halving it and adding the left x protrusion width.
+ *
+ * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
+ * and position it in the most space efficient manner
+ *
+ * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
+ */
+
+ var plFont = getPointLabelFontOptions(scale);
+
+ // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
+ // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
+ var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
+ var furthestLimits = {
+ r: scale.width,
+ l: 0,
+ t: scale.height,
+ b: 0
+ };
+ var furthestAngles = {};
+ var i;
+ var textSize;
+ var pointPosition;
+
+ scale.ctx.font = plFont.font;
+ scale._pointLabelSizes = [];
+
+ var valueCount = getValueCount(scale);
+ for (i = 0; i < valueCount; i++) {
+ pointPosition = scale.getPointPosition(i, largestPossibleRadius);
+ textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
+ scale._pointLabelSizes[i] = textSize;
+
+ // Add quarter circle to make degree 0 mean top of circle
+ var angleRadians = scale.getIndexAngle(i);
+ var angle = helpers.toDegrees(angleRadians) % 360;
+ var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
+ var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
+
+ if (hLimits.start < furthestLimits.l) {
+ furthestLimits.l = hLimits.start;
+ furthestAngles.l = angleRadians;
+ }
+
+ if (hLimits.end > furthestLimits.r) {
+ furthestLimits.r = hLimits.end;
+ furthestAngles.r = angleRadians;
+ }
+
+ if (vLimits.start < furthestLimits.t) {
+ furthestLimits.t = vLimits.start;
+ furthestAngles.t = angleRadians;
+ }
+
+ if (vLimits.end > furthestLimits.b) {
+ furthestLimits.b = vLimits.end;
+ furthestAngles.b = angleRadians;
+ }
+ }
+
+ scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
+ }
+
+ /**
+ * Helper function to fit a radial linear scale with no point labels
+ */
+ function fit(scale) {
+ var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
+ scale.drawingArea = Math.round(largestPossibleRadius);
+ scale.setCenterPoint(0, 0, 0, 0);
+ }
+
+ function getTextAlignForAngle(angle) {
+ if (angle === 0 || angle === 180) {
+ return 'center';
+ } else if (angle < 180) {
+ return 'left';
+ }
+
+ return 'right';
+ }
+
+ function fillText(ctx, text, position, fontSize) {
+ if (helpers.isArray(text)) {
+ var y = position.y;
+ var spacing = 1.5 * fontSize;
+
+ for (var i = 0; i < text.length; ++i) {
+ ctx.fillText(text[i], position.x, y);
+ y+= spacing;
+ }
+ } else {
+ ctx.fillText(text, position.x, position.y);
+ }
+ }
+
+ function adjustPointPositionForLabelHeight(angle, textSize, position) {
+ if (angle === 90 || angle === 270) {
+ position.y -= (textSize.h / 2);
+ } else if (angle > 270 || angle < 90) {
+ position.y -= textSize.h;
+ }
+ }
+
+ function drawPointLabels(scale) {
+ var ctx = scale.ctx;
+ var getValueOrDefault = helpers.getValueOrDefault;
+ var opts = scale.options;
+ var angleLineOpts = opts.angleLines;
+ var pointLabelOpts = opts.pointLabels;
+
+ ctx.lineWidth = angleLineOpts.lineWidth;
+ ctx.strokeStyle = angleLineOpts.color;
+
+ var outerDistance = scale.getDistanceFromCenterForValue(opts.reverse ? scale.min : scale.max);
+
+ // Point Label Font
+ var plFont = getPointLabelFontOptions(scale);
+
+ ctx.textBaseline = 'top';
+
+ for (var i = getValueCount(scale) - 1; i >= 0; i--) {
+ if (angleLineOpts.display) {
+ var outerPosition = scale.getPointPosition(i, outerDistance);
+ ctx.beginPath();
+ ctx.moveTo(scale.xCenter, scale.yCenter);
+ ctx.lineTo(outerPosition.x, outerPosition.y);
+ ctx.stroke();
+ ctx.closePath();
+ }
+
+ if (pointLabelOpts.display) {
+ // Extra 3px out for some label spacing
+ var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
+
+ // Keep this in loop since we may support array properties here
+ var pointLabelFontColor = getValueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor);
+ ctx.font = plFont.font;
+ ctx.fillStyle = pointLabelFontColor;
+
+ var angleRadians = scale.getIndexAngle(i);
+ var angle = helpers.toDegrees(angleRadians);
+ ctx.textAlign = getTextAlignForAngle(angle);
+ adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
+ fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
+ }
+ }
+ }
+
+ function drawRadiusLine(scale, gridLineOpts, radius, index) {
+ var ctx = scale.ctx;
+ ctx.strokeStyle = helpers.getValueAtIndexOrDefault(gridLineOpts.color, index - 1);
+ ctx.lineWidth = helpers.getValueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
+
+ if (scale.options.gridLines.circular) {
+ // Draw circular arcs between the points
+ ctx.beginPath();
+ ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
+ ctx.closePath();
+ ctx.stroke();
+ } else {
+ // Draw straight lines connecting each index
+ var valueCount = getValueCount(scale);
+
+ if (valueCount === 0) {
+ return;
+ }
+
+ ctx.beginPath();
+ var pointPosition = scale.getPointPosition(0, radius);
+ ctx.moveTo(pointPosition.x, pointPosition.y);
+
+ for (var i = 1; i < valueCount; i++) {
+ pointPosition = scale.getPointPosition(i, radius);
+ ctx.lineTo(pointPosition.x, pointPosition.y);
+ }
+
+ ctx.closePath();
+ ctx.stroke();
+ }
+ }
+
+ function numberOrZero(param) {
+ return helpers.isNumber(param) ? param : 0;
+ }
+
+ var LinearRadialScale = Chart.LinearScaleBase.extend({
+ setDimensions: function() {
+ var me = this;
+ var opts = me.options;
+ var tickOpts = opts.ticks;
+ // Set the unconstrained dimension before label rotation
+ me.width = me.maxWidth;
+ me.height = me.maxHeight;
+ me.xCenter = Math.round(me.width / 2);
+ me.yCenter = Math.round(me.height / 2);
+
+ var minSize = helpers.min([me.height, me.width]);
+ var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
+ me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
+ },
+ determineDataLimits: function() {
+ var me = this;
+ var chart = me.chart;
+ var min = Number.POSITIVE_INFINITY;
+ var max = Number.NEGATIVE_INFINITY;
+
+ helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
+ if (chart.isDatasetVisible(datasetIndex)) {
+ var meta = chart.getDatasetMeta(datasetIndex);
+
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +me.getRightValue(rawValue);
+ if (isNaN(value) || meta.data[index].hidden) {
+ return;
+ }
+
+ min = Math.min(value, min);
+ max = Math.max(value, max);
+ });
+ }
+ });
+
+ me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
+ me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
+
+ // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
+ me.handleTickRangeOptions();
+ },
+ getTickLimit: function() {
+ var tickOpts = this.options.ticks;
+ var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
+ return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
+ },
+ convertTicksToLabels: function() {
+ var me = this;
+ Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);
+
+ // Point labels
+ me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
+ },
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+ fit: function() {
+ if (this.options.pointLabels.display) {
+ fitWithPointLabels(this);
+ } else {
+ fit(this);
+ }
+ },
+ /**
+ * Set radius reductions and determine new radius and center point
+ * @private
+ */
+ setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
+ var me = this;
+ var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
+ var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
+ var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
+ var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
+
+ radiusReductionLeft = numberOrZero(radiusReductionLeft);
+ radiusReductionRight = numberOrZero(radiusReductionRight);
+ radiusReductionTop = numberOrZero(radiusReductionTop);
+ radiusReductionBottom = numberOrZero(radiusReductionBottom);
+
+ me.drawingArea = Math.min(
+ Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
+ Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
+ me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
+ },
+ setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
+ var me = this;
+ var maxRight = me.width - rightMovement - me.drawingArea,
+ maxLeft = leftMovement + me.drawingArea,
+ maxTop = topMovement + me.drawingArea,
+ maxBottom = me.height - bottomMovement - me.drawingArea;
+
+ me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
+ me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
+ },
+
+ getIndexAngle: function(index) {
+ var angleMultiplier = (Math.PI * 2) / getValueCount(this);
+ var startAngle = this.chart.options && this.chart.options.startAngle ?
+ this.chart.options.startAngle :
+ 0;
+
+ var startAngleRadians = startAngle * Math.PI * 2 / 360;
+
+ // Start from the top instead of right, so remove a quarter of the circle
+ return index * angleMultiplier + startAngleRadians;
+ },
+ getDistanceFromCenterForValue: function(value) {
+ var me = this;
+
+ if (value === null) {
+ return 0; // null always in center
+ }
+
+ // Take into account half font size + the yPadding of the top value
+ var scalingFactor = me.drawingArea / (me.max - me.min);
+ if (me.options.reverse) {
+ return (me.max - value) * scalingFactor;
+ }
+ return (value - me.min) * scalingFactor;
+ },
+ getPointPosition: function(index, distanceFromCenter) {
+ var me = this;
+ var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
+ return {
+ x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
+ y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
+ };
+ },
+ getPointPositionForValue: function(index, value) {
+ return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
+ },
+
+ getBasePosition: function() {
+ var me = this;
+ var min = me.min;
+ var max = me.max;
+
+ return me.getPointPositionForValue(0,
+ me.beginAtZero? 0:
+ min < 0 && max < 0? max :
+ min > 0 && max > 0? min :
+ 0);
+ },
+
+ draw: function() {
+ var me = this;
+ var opts = me.options;
+ var gridLineOpts = opts.gridLines;
+ var tickOpts = opts.ticks;
+ var getValueOrDefault = helpers.getValueOrDefault;
+
+ if (opts.display) {
+ var ctx = me.ctx;
+
+ // Tick Font
+ var tickFontSize = getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
+ var tickFontStyle = getValueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
+ var tickFontFamily = getValueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
+ var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
+
+ helpers.each(me.ticks, function(label, index) {
+ // Don't draw a centre value (if it is minimum)
+ if (index > 0 || opts.reverse) {
+ var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
+ var yHeight = me.yCenter - yCenterOffset;
+
+ // Draw circular lines around the scale
+ if (gridLineOpts.display && index !== 0) {
+ drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
+ }
+
+ if (tickOpts.display) {
+ var tickFontColor = getValueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
+ ctx.font = tickLabelFont;
+
+ if (tickOpts.showLabelBackdrop) {
+ var labelWidth = ctx.measureText(label).width;
+ ctx.fillStyle = tickOpts.backdropColor;
+ ctx.fillRect(
+ me.xCenter - labelWidth / 2 - tickOpts.backdropPaddingX,
+ yHeight - tickFontSize / 2 - tickOpts.backdropPaddingY,
+ labelWidth + tickOpts.backdropPaddingX * 2,
+ tickFontSize + tickOpts.backdropPaddingY * 2
+ );
+ }
+
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillStyle = tickFontColor;
+ ctx.fillText(label, me.xCenter, yHeight);
+ }
+ }
+ });
+
+ if (opts.angleLines.display || opts.pointLabels.display) {
+ drawPointLabels(me);
+ }
+ }
+ }
+ });
+ Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);
+
+};
+
+},{}],49:[function(require,module,exports){
+/* global window: false */
+'use strict';
+
+var moment = require(1);
+moment = typeof(moment) === 'function' ? moment : window.moment;
+
+module.exports = function(Chart) {
+
+ var helpers = Chart.helpers;
+ var interval = {
+ millisecond: {
+ size: 1,
+ steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
+ },
+ second: {
+ size: 1000,
+ steps: [1, 2, 5, 10, 30]
+ },
+ minute: {
+ size: 60000,
+ steps: [1, 2, 5, 10, 30]
+ },
+ hour: {
+ size: 3600000,
+ steps: [1, 2, 3, 6, 12]
+ },
+ day: {
+ size: 86400000,
+ steps: [1, 2, 5]
+ },
+ week: {
+ size: 604800000,
+ maxStep: 4
+ },
+ month: {
+ size: 2.628e9,
+ maxStep: 3
+ },
+ quarter: {
+ size: 7.884e9,
+ maxStep: 4
+ },
+ year: {
+ size: 3.154e10,
+ maxStep: false
+ }
+ };
+
+ var defaultConfig = {
+ position: 'bottom',
+
+ time: {
+ parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
+ format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
+ unit: false, // false == automatic or override with week, month, year, etc.
+ round: false, // none, or override with week, month, year, etc.
+ displayFormat: false, // DEPRECATED
+ isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
+ minUnit: 'millisecond',
+
+ // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
+ displayFormats: {
+ millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
+ second: 'h:mm:ss a', // 11:20:01 AM
+ minute: 'h:mm:ss a', // 11:20:01 AM
+ hour: 'MMM D, hA', // Sept 4, 5PM
+ day: 'll', // Sep 4 2015
+ week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
+ month: 'MMM YYYY', // Sept 2015
+ quarter: '[Q]Q - YYYY', // Q3
+ year: 'YYYY' // 2015
+ },
+ },
+ ticks: {
+ autoSkip: false
+ }
+ };
+
+ /**
+ * Helper function to parse time to a moment object
+ * @param axis {TimeAxis} the time axis
+ * @param label {Date|string|number|Moment} The thing to parse
+ * @return {Moment} parsed time
+ */
+ function parseTime(axis, label) {
+ var timeOpts = axis.options.time;
+ if (typeof timeOpts.parser === 'string') {
+ return moment(label, timeOpts.parser);
+ }
+ if (typeof timeOpts.parser === 'function') {
+ return timeOpts.parser(label);
+ }
+ if (typeof label.getMonth === 'function' || typeof label === 'number') {
+ // Date objects
+ return moment(label);
+ }
+ if (label.isValid && label.isValid()) {
+ // Moment support
+ return label;
+ }
+ var format = timeOpts.format;
+ if (typeof format !== 'string' && format.call) {
+ // Custom parsing (return an instance of moment)
+ console.warn('options.time.format is deprecated and replaced by options.time.parser.');
+ return format(label);
+ }
+ // Moment format parsing
+ return moment(label, format);
+ }
+
+ /**
+ * Figure out which is the best unit for the scale
+ * @param minUnit {String} minimum unit to use
+ * @param min {Number} scale minimum
+ * @param max {Number} scale maximum
+ * @return {String} the unit to use
+ */
+ function determineUnit(minUnit, min, max, maxTicks) {
+ var units = Object.keys(interval);
+ var unit;
+ var numUnits = units.length;
+
+ for (var i = units.indexOf(minUnit); i < numUnits; i++) {
+ unit = units[i];
+ var unitDetails = interval[unit];
+ var steps = (unitDetails.steps && unitDetails.steps[unitDetails.steps.length - 1]) || unitDetails.maxStep;
+ if (steps === undefined || Math.ceil((max - min) / (steps * unitDetails.size)) <= maxTicks) {
+ break;
+ }
+ }
+
+ return unit;
+ }
+
+ /**
+ * Determines how we scale the unit
+ * @param min {Number} the scale minimum
+ * @param max {Number} the scale maximum
+ * @param unit {String} the unit determined by the {@see determineUnit} method
+ * @return {Number} the axis step size as a multiple of unit
+ */
+ function determineStepSize(min, max, unit, maxTicks) {
+ // Using our unit, figoure out what we need to scale as
+ var unitDefinition = interval[unit];
+ var unitSizeInMilliSeconds = unitDefinition.size;
+ var sizeInUnits = Math.ceil((max - min) / unitSizeInMilliSeconds);
+ var multiplier = 1;
+ var range = max - min;
+
+ if (unitDefinition.steps) {
+ // Have an array of steps
+ var numSteps = unitDefinition.steps.length;
+ for (var i = 0; i < numSteps && sizeInUnits > maxTicks; i++) {
+ multiplier = unitDefinition.steps[i];
+ sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
+ }
+ } else {
+ while (sizeInUnits > maxTicks && maxTicks > 0) {
+ ++multiplier;
+ sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
+ }
+ }
+
+ return multiplier;
+ }
+
+ /**
+ * Helper for generating axis labels.
+ * @param options {ITimeGeneratorOptions} the options for generation
+ * @param dataRange {IRange} the data range
+ * @param niceRange {IRange} the pretty range to display
+ * @return {Number[]} ticks
+ */
+ function generateTicks(options, dataRange, niceRange) {
+ var ticks = [];
+ if (options.maxTicks) {
+ var stepSize = options.stepSize;
+ ticks.push(options.min !== undefined ? options.min : niceRange.min);
+ var cur = moment(niceRange.min);
+ while (cur.add(stepSize, options.unit).valueOf() < niceRange.max) {
+ ticks.push(cur.valueOf());
+ }
+ var realMax = options.max || niceRange.max;
+ if (ticks[ticks.length - 1] !== realMax) {
+ ticks.push(realMax);
+ }
+ }
+ return ticks;
+ }
+
+ /**
+ * @function Chart.Ticks.generators.time
+ * @param options {ITimeGeneratorOptions} the options for generation
+ * @param dataRange {IRange} the data range
+ * @return {Number[]} ticks
+ */
+ Chart.Ticks.generators.time = function(options, dataRange) {
+ var niceMin;
+ var niceMax;
+ var isoWeekday = options.isoWeekday;
+ if (options.unit === 'week' && isoWeekday !== false) {
+ niceMin = moment(dataRange.min).startOf('isoWeek').isoWeekday(isoWeekday).valueOf();
+ niceMax = moment(dataRange.max).startOf('isoWeek').isoWeekday(isoWeekday);
+ if (dataRange.max - niceMax > 0) {
+ niceMax.add(1, 'week');
+ }
+ niceMax = niceMax.valueOf();
+ } else {
+ niceMin = moment(dataRange.min).startOf(options.unit).valueOf();
+ niceMax = moment(dataRange.max).startOf(options.unit);
+ if (dataRange.max - niceMax > 0) {
+ niceMax.add(1, options.unit);
+ }
+ niceMax = niceMax.valueOf();
+ }
+ return generateTicks(options, dataRange, {
+ min: niceMin,
+ max: niceMax
+ });
+ };
+
+ var TimeScale = Chart.Scale.extend({
+ initialize: function() {
+ if (!moment) {
+ throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
+ }
+
+ Chart.Scale.prototype.initialize.call(this);
+ },
+ determineDataLimits: function() {
+ var me = this;
+ var timeOpts = me.options.time;
+
+ // We store the data range as unix millisecond timestamps so dataMin and dataMax will always be integers.
+ var dataMin = Number.MAX_SAFE_INTEGER;
+ var dataMax = Number.MIN_SAFE_INTEGER;
+
+ var chartData = me.chart.data;
+ var parsedData = {
+ labels: [],
+ datasets: []
+ };
+
+ var timestamp;
+
+ helpers.each(chartData.labels, function(label, labelIndex) {
+ var labelMoment = parseTime(me, label);
+
+ if (labelMoment.isValid()) {
+ // We need to round the time
+ if (timeOpts.round) {
+ labelMoment.startOf(timeOpts.round);
+ }
+
+ timestamp = labelMoment.valueOf();
+ dataMin = Math.min(timestamp, dataMin);
+ dataMax = Math.max(timestamp, dataMax);
+
+ // Store this value for later
+ parsedData.labels[labelIndex] = timestamp;
+ }
+ });
+
+ helpers.each(chartData.datasets, function(dataset, datasetIndex) {
+ var timestamps = [];
+
+ if (typeof dataset.data[0] === 'object' && dataset.data[0] !== null && me.chart.isDatasetVisible(datasetIndex)) {
+ // We have potential point data, so we need to parse this
+ helpers.each(dataset.data, function(value, dataIndex) {
+ var dataMoment = parseTime(me, me.getRightValue(value));
+
+ if (dataMoment.isValid()) {
+ if (timeOpts.round) {
+ dataMoment.startOf(timeOpts.round);
+ }
+
+ timestamp = dataMoment.valueOf();
+ dataMin = Math.min(timestamp, dataMin);
+ dataMax = Math.max(timestamp, dataMax);
+ timestamps[dataIndex] = timestamp;
+ }
+ });
+ } else {
+ // We have no x coordinates, so use the ones from the labels
+ timestamps = parsedData.labels.slice();
+ }
+
+ parsedData.datasets[datasetIndex] = timestamps;
+ });
+
+ me.dataMin = dataMin;
+ me.dataMax = dataMax;
+ me._parsedData = parsedData;
+ },
+ buildTicks: function() {
+ var me = this;
+ var timeOpts = me.options.time;
+
+ var minTimestamp;
+ var maxTimestamp;
+ var dataMin = me.dataMin;
+ var dataMax = me.dataMax;
+
+ if (timeOpts.min) {
+ var minMoment = parseTime(me, timeOpts.min);
+ if (timeOpts.round) {
+ minMoment.round(timeOpts.round);
+ }
+ minTimestamp = minMoment.valueOf();
+ }
+
+ if (timeOpts.max) {
+ maxTimestamp = parseTime(me, timeOpts.max).valueOf();
+ }
+
+ var maxTicks = me.getLabelCapacity(minTimestamp || dataMin);
+ var unit = timeOpts.unit || determineUnit(timeOpts.minUnit, minTimestamp || dataMin, maxTimestamp || dataMax, maxTicks);
+ me.displayFormat = timeOpts.displayFormats[unit];
+
+ var stepSize = timeOpts.stepSize || determineStepSize(minTimestamp || dataMin, maxTimestamp || dataMax, unit, maxTicks);
+ me.ticks = Chart.Ticks.generators.time({
+ maxTicks: maxTicks,
+ min: minTimestamp,
+ max: maxTimestamp,
+ stepSize: stepSize,
+ unit: unit,
+ isoWeekday: timeOpts.isoWeekday
+ }, {
+ min: dataMin,
+ max: dataMax
+ });
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ me.max = helpers.max(me.ticks);
+ me.min = helpers.min(me.ticks);
+ },
+ // Get tooltip label
+ getLabelForIndex: function(index, datasetIndex) {
+ var me = this;
+ var label = me.chart.data.labels && index < me.chart.data.labels.length ? me.chart.data.labels[index] : '';
+ var value = me.chart.data.datasets[datasetIndex].data[index];
+
+ if (value !== null && typeof value === 'object') {
+ label = me.getRightValue(value);
+ }
+
+ // Format nicely
+ if (me.options.time.tooltipFormat) {
+ label = parseTime(me, label).format(me.options.time.tooltipFormat);
+ }
+
+ return label;
+ },
+ // Function to format an individual tick mark
+ tickFormatFunction: function(tick, index, ticks) {
+ var formattedTick = tick.format(this.displayFormat);
+ var tickOpts = this.options.ticks;
+ var callback = helpers.getValueOrDefault(tickOpts.callback, tickOpts.userCallback);
+
+ if (callback) {
+ return callback(formattedTick, index, ticks);
+ }
+ return formattedTick;
+ },
+ convertTicksToLabels: function() {
+ var me = this;
+ me.ticksAsTimestamps = me.ticks;
+ me.ticks = me.ticks.map(function(tick) {
+ return moment(tick);
+ }).map(me.tickFormatFunction, me);
+ },
+ getPixelForOffset: function(offset) {
+ var me = this;
+ var epochWidth = me.max - me.min;
+ var decimal = epochWidth ? (offset - me.min) / epochWidth : 0;
+
+ if (me.isHorizontal()) {
+ var valueOffset = (me.width * decimal);
+ return me.left + Math.round(valueOffset);
+ }
+
+ var heightOffset = (me.height * decimal);
+ return me.top + Math.round(heightOffset);
+ },
+ getPixelForValue: function(value, index, datasetIndex) {
+ var me = this;
+ var offset = null;
+ if (index !== undefined && datasetIndex !== undefined) {
+ offset = me._parsedData.datasets[datasetIndex][index];
+ }
+
+ if (offset === null) {
+ if (!value || !value.isValid) {
+ // not already a moment object
+ value = parseTime(me, me.getRightValue(value));
+ }
+
+ if (value && value.isValid && value.isValid()) {
+ offset = value.valueOf();
+ }
+ }
+
+ if (offset !== null) {
+ return me.getPixelForOffset(offset);
+ }
+ },
+ getPixelForTick: function(index) {
+ return this.getPixelForOffset(this.ticksAsTimestamps[index]);
+ },
+ getValueForPixel: function(pixel) {
+ var me = this;
+ var innerDimension = me.isHorizontal() ? me.width : me.height;
+ var offset = (pixel - (me.isHorizontal() ? me.left : me.top)) / innerDimension;
+ return moment(me.min + (offset * (me.max - me.min)));
+ },
+ // Crude approximation of what the label width might be
+ getLabelWidth: function(label) {
+ var me = this;
+ var ticks = me.options.ticks;
+
+ var tickLabelWidth = me.ctx.measureText(label).width;
+ var cosRotation = Math.cos(helpers.toRadians(ticks.maxRotation));
+ var sinRotation = Math.sin(helpers.toRadians(ticks.maxRotation));
+ var tickFontSize = helpers.getValueOrDefault(ticks.fontSize, Chart.defaults.global.defaultFontSize);
+ return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
+ },
+ getLabelCapacity: function(exampleTime) {
+ var me = this;
+
+ me.displayFormat = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
+ var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, []);
+ var tickLabelWidth = me.getLabelWidth(exampleLabel);
+
+ var innerWidth = me.isHorizontal() ? me.width : me.height;
+ var labelCapacity = innerWidth / tickLabelWidth;
+ return labelCapacity;
+ }
+ });
+ Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig);
+
+};
+
+},{"1":1}]},{},[7])(7)
+});
\ No newline at end of file
diff --git a/contao/assets/chartjs/dist/Chart.min.js b/contao/assets/chartjs/dist/Chart.min.js
new file mode 100644
index 0000000..3e93936
--- /dev/null
+++ b/contao/assets/chartjs/dist/Chart.min.js
@@ -0,0 +1,14 @@
+/*!
+ * Chart.js
+ * http://chartjs.org/
+ * Version: 2.6.0
+ *
+ * Copyright 2017 Nick Downie
+ * Released under the MIT license
+ * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
+ */
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Chart=t()}}(function(){return function t(e,n,i){function a(r,l){if(!n[r]){if(!e[r]){var s="function"==typeof require&&require;if(!l&&s)return s(r,!0);if(o)return o(r,!0);var u=new Error("Cannot find module '"+r+"'");throw u.code="MODULE_NOT_FOUND",u}var d=n[r]={exports:{}};e[r][0].call(d.exports,function(t){var n=e[r][1][t];return a(n?n:t)},d,d.exports,t,e,n,i)}return n[r].exports}for(var o="function"==typeof require&&require,r=0;rn?(e+.05)/(n+.05):(n+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb,e=(299*t[0]+587*t[1]+114*t[2])/1e3;return e<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,n=(e[0]+t)%360;return e[0]=n<0?360+n:n,this.setValues("hsl",e),this},mix:function(t,e){var n=this,i=t,a=void 0===e?.5:e,o=2*a-1,r=n.alpha()-i.alpha(),l=((o*r===-1?o:(o+r)/(1+o*r))+1)/2,s=1-l;return this.rgb(l*n.red()+s*i.red(),l*n.green()+s*i.green(),l*n.blue()+s*i.blue()).alpha(n.alpha()*a+i.alpha()*(1-a))},toJSON:function(){return this.rgb()},clone:function(){var t,e,n=new o,i=this.values,a=n.values;for(var r in i)i.hasOwnProperty(r)&&(t=i[r],e={}.toString.call(t),"[object Array]"===e?a[r]=t.slice(0):"[object Number]"===e?a[r]=t:console.error("unexpected color value:",t));return n}},o.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},o.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},o.prototype.getValues=function(t){for(var e=this.values,n={},i=0;i.04045?Math.pow((e+.055)/1.055,2.4):e/12.92,n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92,i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92;var a=.4124*e+.3576*n+.1805*i,o=.2126*e+.7152*n+.0722*i,r=.0193*e+.1192*n+.9505*i;return[100*a,100*o,100*r]}function d(t){var e,n,i,a=u(t),o=a[0],r=a[1],l=a[2];return o/=95.047,r/=100,l/=108.883,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,l=l>.008856?Math.pow(l,1/3):7.787*l+16/116,e=116*r-16,n=500*(o-r),i=200*(r-l),[e,n,i]}function c(t){return B(d(t))}function h(t){var e,n,i,a,o,r=t[0]/360,l=t[1]/100,s=t[2]/100;if(0==l)return o=255*s,[o,o,o];n=s<.5?s*(1+l):s+l-s*l,e=2*s-n,a=[0,0,0];for(var u=0;u<3;u++)i=r+1/3*-(u-1),i<0&&i++,i>1&&i--,o=6*i<1?e+6*(n-e)*i:2*i<1?n:3*i<2?e+(n-e)*(2/3-i)*6:e,a[u]=255*o;return a}function f(t){var e,n,i=t[0],a=t[1]/100,o=t[2]/100;return 0===o?[0,0,0]:(o*=2,a*=o<=1?o:2-o,n=(o+a)/2,e=2*a/(o+a),[i,100*e,100*n])}function p(t){return o(h(t))}function m(t){return l(h(t))}function v(t){return s(h(t))}function x(t){var e=t[0]/60,n=t[1]/100,i=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),r=255*i*(1-n),l=255*i*(1-n*o),s=255*i*(1-n*(1-o)),i=255*i;switch(a){case 0:return[i,s,r];case 1:return[l,i,r];case 2:return[r,i,s];case 3:return[r,l,i];case 4:return[s,r,i];case 5:return[i,r,l]}}function y(t){var e,n,i=t[0],a=t[1]/100,o=t[2]/100;return n=(2-a)*o,e=a*o,e/=n<=1?n:2-n,e=e||0,n/=2,[i,100*e,100*n]}function k(t){return o(x(t))}function w(t){return l(x(t))}function M(t){return s(x(t))}function S(t){var e,n,i,a,o=t[0]/360,l=t[1]/100,s=t[2]/100,u=l+s;switch(u>1&&(l/=u,s/=u),e=Math.floor(6*o),n=1-s,i=6*o-e,0!=(1&e)&&(i=1-i),a=l+i*(n-l),e){default:case 6:case 0:r=n,g=a,b=l;break;case 1:r=a,g=n,b=l;break;case 2:r=l,g=n,b=a;break;case 3:r=l,g=a,b=n;break;case 4:r=a,g=l,b=n;break;case 5:r=n,g=l,b=a}return[255*r,255*g,255*b]}function C(t){return i(S(t))}function D(t){return a(S(t))}function I(t){return l(S(t))}function A(t){return s(S(t))}function P(t){var e,n,i,a=t[0]/100,o=t[1]/100,r=t[2]/100,l=t[3]/100;return e=1-Math.min(1,a*(1-l)+l),n=1-Math.min(1,o*(1-l)+l),i=1-Math.min(1,r*(1-l)+l),[255*e,255*n,255*i]}function _(t){return i(P(t))}function T(t){return a(P(t))}function F(t){return o(P(t))}function R(t){return s(P(t))}function L(t){var e,n,i,a=t[0]/100,o=t[1]/100,r=t[2]/100;return e=3.2406*a+o*-1.5372+r*-.4986,n=a*-.9689+1.8758*o+.0415*r,i=.0557*a+o*-.204+1.057*r,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:e*=12.92,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,e=Math.min(Math.max(0,e),1),n=Math.min(Math.max(0,n),1),i=Math.min(Math.max(0,i),1),[255*e,255*n,255*i]}function V(t){var e,n,i,a=t[0],o=t[1],r=t[2];return a/=95.047,o/=100,r/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,e=116*o-16,n=500*(a-o),i=200*(o-r),[e,n,i]}function O(t){return B(V(t))}function z(t){var e,n,i,a,o=t[0],r=t[1],l=t[2];return o<=8?(n=100*o/903.3,a=7.787*(n/100)+16/116):(n=100*Math.pow((o+16)/116,3),a=Math.pow(n/100,1/3)),e=e/95.047<=.008856?e=95.047*(r/500+a-16/116)/7.787:95.047*Math.pow(r/500+a,3),i=i/108.883<=.008859?i=108.883*(a-l/200-16/116)/7.787:108.883*Math.pow(a-l/200,3),[e,n,i]}function B(t){var e,n,i,a=t[0],o=t[1],r=t[2];return e=Math.atan2(r,o),n=360*e/2/Math.PI,n<0&&(n+=360),i=Math.sqrt(o*o+r*r),[a,i,n]}function W(t){return L(z(t))}function N(t){var e,n,i,a=t[0],o=t[1],r=t[2];return i=r/360*2*Math.PI,e=o*Math.cos(i),n=o*Math.sin(i),[a,e,n]}function E(t){return z(N(t))}function H(t){return W(N(t))}function q(t){return J[t]}function j(t){return i(q(t))}function Y(t){return a(q(t))}function U(t){return o(q(t))}function X(t){return l(q(t))}function K(t){return d(q(t))}function G(t){return u(q(t))}e.exports={rgb2hsl:i,rgb2hsv:a,rgb2hwb:o,rgb2cmyk:l,rgb2keyword:s,rgb2xyz:u,rgb2lab:d,rgb2lch:c,hsl2rgb:h,hsl2hsv:f,hsl2hwb:p,hsl2cmyk:m,hsl2keyword:v,hsv2rgb:x,hsv2hsl:y,hsv2hwb:k,hsv2cmyk:w,hsv2keyword:M,hwb2rgb:S,hwb2hsl:C,hwb2hsv:D,hwb2cmyk:I,hwb2keyword:A,cmyk2rgb:P,cmyk2hsl:_,cmyk2hsv:T,cmyk2hwb:F,cmyk2keyword:R,keyword2rgb:q,keyword2hsl:j,keyword2hsv:Y,keyword2hwb:U,keyword2cmyk:X,keyword2lab:K,keyword2xyz:G,xyz2rgb:L,xyz2lab:V,xyz2lch:O,lab2xyz:z,lab2rgb:W,lab2lch:B,lch2lab:N,lch2xyz:E,lch2rgb:H};var J={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]},Z={};for(var Q in J)Z[JSON.stringify(J[Q])]=Q},{}],5:[function(t,e,n){var i=t(4),a=function(){return new u};for(var o in i){a[o+"Raw"]=function(t){return function(e){return"number"==typeof e&&(e=Array.prototype.slice.call(arguments)),i[t](e)}}(o);var r=/(\w+)2(\w+)/.exec(o),l=r[1],s=r[2];a[l]=a[l]||{},a[l][s]=a[o]=function(t){return function(e){"number"==typeof e&&(e=Array.prototype.slice.call(arguments));var n=i[t](e);if("string"==typeof n||void 0===n)return n;for(var a=0;a=0&&a>0)&&(m+=a));return o=c.getPixelForValue(m),r=c.getPixelForValue(m+f),l=(r-o)/2,{size:l,base:o,head:r,center:r+l/2}},calculateBarIndexPixels:function(t,e,n){var i=this,a=n.scale,o=i.chart.isCombo,r=i.getStackIndex(t),l=a.getPixelForValue(null,e,t,o),s=n.barSize;return l-=o?n.tickSize/2:0,l+=n.fullBarSize*r,l+=n.categorySpacing/2,l+=n.barSpacing/2,{size:s,base:l,head:l+s,center:l+s/2}},draw:function(){var t,n=this,i=n.chart,a=n.getMeta().data,o=n.getDataset(),r=a.length,l=0;for(e.canvas.clipArea(i.ctx,i.chartArea);l0&&(t[0].yLabel?n=t[0].yLabel:e.labels.length>0&&t[0].index');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var o=0;o '),a[o]&&e.push(a[o]),e.push("");return e.push(""),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var o=t.getDatasetMeta(0),r=n.datasets[0],l=o.data[a],s=l&&l.custom||{},u=e.getValueAtIndexOrDefault,d=t.options.elements.arc,c=s.backgroundColor?s.backgroundColor:u(r.backgroundColor,a,d.backgroundColor),h=s.borderColor?s.borderColor:u(r.borderColor,a,d.borderColor),f=s.borderWidth?s.borderWidth:u(r.borderWidth,a,d.borderWidth);return{text:i,fillStyle:c,strokeStyle:h,lineWidth:f,hidden:isNaN(r.data[a])||o.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,o=e.index,r=this.chart;for(n=0,i=(r.data.datasets||[]).length;n=Math.PI?-1:g<-Math.PI?1:0);var p=g+f,m={x:Math.cos(g),y:Math.sin(g)},v={x:Math.cos(p),y:Math.sin(p)},b=g<=0&&0<=p||g<=2*Math.PI&&2*Math.PI<=p,x=g<=.5*Math.PI&&.5*Math.PI<=p||g<=2.5*Math.PI&&2.5*Math.PI<=p,y=g<=-Math.PI&&-Math.PI<=p||g<=Math.PI&&Math.PI<=p,k=g<=.5*-Math.PI&&.5*-Math.PI<=p||g<=1.5*Math.PI&&1.5*Math.PI<=p,w=h/100,M={x:y?-1:Math.min(m.x*(m.x<0?1:w),v.x*(v.x<0?1:w)),y:k?-1:Math.min(m.y*(m.y<0?1:w),v.y*(v.y<0?1:w))},S={x:b?1:Math.max(m.x*(m.x>0?1:w),v.x*(v.x>0?1:w)),y:x?1:Math.max(m.y*(m.y>0?1:w),v.y*(v.y>0?1:w))},C={width:.5*(S.x-M.x),height:.5*(S.y-M.y)};u=Math.min(l/C.width,s/C.height),d={x:(S.x+M.x)*-.5,y:(S.y+M.y)*-.5}}i.borderWidth=n.getMaxBorderWidth(c.data),i.outerRadius=Math.max((u-i.borderWidth)/2,0),i.innerRadius=Math.max(h?i.outerRadius/100*h:0,0),i.radiusLength=(i.outerRadius-i.innerRadius)/i.getVisibleDatasetCount(),i.offsetX=d.x*i.outerRadius,i.offsetY=d.y*i.outerRadius,c.total=n.calculateTotal(),n.outerRadius=i.outerRadius-i.radiusLength*n.getRingIndex(n.index),n.innerRadius=Math.max(n.outerRadius-i.radiusLength,0),e.each(c.data,function(e,i){n.updateElement(e,i,t)})},updateElement:function(t,n,i){var a=this,o=a.chart,r=o.chartArea,l=o.options,s=l.animation,u=(r.left+r.right)/2,d=(r.top+r.bottom)/2,c=l.rotation,h=l.rotation,f=a.getDataset(),g=i&&s.animateRotate?0:t.hidden?0:a.calculateCircumference(f.data[n])*(l.circumference/(2*Math.PI)),p=i&&s.animateScale?0:a.innerRadius,m=i&&s.animateScale?0:a.outerRadius,v=e.getValueAtIndexOrDefault;e.extend(t,{_datasetIndex:a.index,_index:n,_model:{x:u+o.offsetX,y:d+o.offsetY,startAngle:c,endAngle:h,circumference:g,outerRadius:m,innerRadius:p,label:v(f.label,n,o.data.labels[n])}});var b=t._model;this.removeHoverStyle(t),i&&s.animateRotate||(0===n?b.startAngle=l.rotation:b.startAngle=a.getMeta().data[n-1]._model.endAngle,b.endAngle=b.startAngle+b.circumference),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},calculateTotal:function(){var t,n=this.getDataset(),i=this.getMeta(),a=0;return e.each(i.data,function(e,i){t=n.data[i],isNaN(t)||e.hidden||(a+=Math.abs(t))}),a},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(t/e):0},getMaxBorderWidth:function(t){for(var e,n,i=0,a=this.index,o=t.length,r=0;ri?e:i,i=n>i?n:i;return i}})}},{}],18:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return n.getValueOrDefault(t.showLine,e.showLines)}var n=t.helpers;t.defaults.line={showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}},t.controllers.line=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,update:function(t){var i,a,o,r=this,l=r.getMeta(),s=l.dataset,u=l.data||[],d=r.chart.options,c=d.elements.line,h=r.getScaleForId(l.yAxisID),f=r.getDataset(),g=e(f,d);for(g&&(o=s.custom||{},void 0!==f.tension&&void 0===f.lineTension&&(f.lineTension=f.tension),s._scale=h,s._datasetIndex=r.index,s._children=u,s._model={spanGaps:f.spanGaps?f.spanGaps:d.spanGaps,tension:o.tension?o.tension:n.getValueOrDefault(f.lineTension,c.tension),backgroundColor:o.backgroundColor?o.backgroundColor:f.backgroundColor||c.backgroundColor,borderWidth:o.borderWidth?o.borderWidth:f.borderWidth||c.borderWidth,borderColor:o.borderColor?o.borderColor:f.borderColor||c.borderColor,borderCapStyle:o.borderCapStyle?o.borderCapStyle:f.borderCapStyle||c.borderCapStyle,borderDash:o.borderDash?o.borderDash:f.borderDash||c.borderDash,borderDashOffset:o.borderDashOffset?o.borderDashOffset:f.borderDashOffset||c.borderDashOffset,borderJoinStyle:o.borderJoinStyle?o.borderJoinStyle:f.borderJoinStyle||c.borderJoinStyle,fill:o.fill?o.fill:void 0!==f.fill?f.fill:c.fill,steppedLine:o.steppedLine?o.steppedLine:n.getValueOrDefault(f.steppedLine,c.stepped),cubicInterpolationMode:o.cubicInterpolationMode?o.cubicInterpolationMode:n.getValueOrDefault(f.cubicInterpolationMode,c.cubicInterpolationMode)},s.pivot()),i=0,a=u.length;i');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var o=0;o '),a[o]&&e.push(a[o]),e.push("");return e.push(""),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var o=t.getDatasetMeta(0),r=n.datasets[0],l=o.data[a],s=l.custom||{},u=e.getValueAtIndexOrDefault,d=t.options.elements.arc,c=s.backgroundColor?s.backgroundColor:u(r.backgroundColor,a,d.backgroundColor),h=s.borderColor?s.borderColor:u(r.borderColor,a,d.borderColor),f=s.borderWidth?s.borderWidth:u(r.borderWidth,a,d.borderWidth);return{text:i,fillStyle:c,strokeStyle:h,lineWidth:f,hidden:isNaN(r.data[a])||o.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,o=e.index,r=this.chart;for(n=0,i=(r.data.datasets||[]).length;n0&&!isNaN(t)?2*Math.PI/e:0}})}},{}],20:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.radar={aspectRatio:1,scale:{type:"radialLinear"},elements:{line:{tension:0}}},t.controllers.radar=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,linkScales:e.noop,update:function(t){var n=this,i=n.getMeta(),a=i.dataset,o=i.data,r=a.custom||{},l=n.getDataset(),s=n.chart.options.elements.line,u=n.chart.scale;void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),e.extend(i.dataset,{_datasetIndex:n.index,_scale:u,_children:o,_loop:!0,_model:{tension:r.tension?r.tension:e.getValueOrDefault(l.lineTension,s.tension),backgroundColor:r.backgroundColor?r.backgroundColor:l.backgroundColor||s.backgroundColor,borderWidth:r.borderWidth?r.borderWidth:l.borderWidth||s.borderWidth,borderColor:r.borderColor?r.borderColor:l.borderColor||s.borderColor,fill:r.fill?r.fill:void 0!==l.fill?l.fill:s.fill,borderCapStyle:r.borderCapStyle?r.borderCapStyle:l.borderCapStyle||s.borderCapStyle,borderDash:r.borderDash?r.borderDash:l.borderDash||s.borderDash,borderDashOffset:r.borderDashOffset?r.borderDashOffset:l.borderDashOffset||s.borderDashOffset,borderJoinStyle:r.borderJoinStyle?r.borderJoinStyle:l.borderJoinStyle||s.borderJoinStyle}}),i.dataset.pivot(),e.each(o,function(e,i){n.updateElement(e,i,t)},n),n.updateBezierControlPoints()},updateElement:function(t,n,i){var a=this,o=t.custom||{},r=a.getDataset(),l=a.chart.scale,s=a.chart.options.elements.point,u=l.getPointPositionForValue(n,r.data[n]);void 0!==r.radius&&void 0===r.pointRadius&&(r.pointRadius=r.radius),void 0!==r.hitRadius&&void 0===r.pointHitRadius&&(r.pointHitRadius=r.hitRadius),e.extend(t,{_datasetIndex:a.index,_index:n,_scale:l,_model:{x:i?l.xCenter:u.x,y:i?l.yCenter:u.y,tension:o.tension?o.tension:e.getValueOrDefault(r.lineTension,a.chart.options.elements.line.tension),radius:o.radius?o.radius:e.getValueAtIndexOrDefault(r.pointRadius,n,s.radius),backgroundColor:o.backgroundColor?o.backgroundColor:e.getValueAtIndexOrDefault(r.pointBackgroundColor,n,s.backgroundColor),borderColor:o.borderColor?o.borderColor:e.getValueAtIndexOrDefault(r.pointBorderColor,n,s.borderColor),borderWidth:o.borderWidth?o.borderWidth:e.getValueAtIndexOrDefault(r.pointBorderWidth,n,s.borderWidth),pointStyle:o.pointStyle?o.pointStyle:e.getValueAtIndexOrDefault(r.pointStyle,n,s.pointStyle),hitRadius:o.hitRadius?o.hitRadius:e.getValueAtIndexOrDefault(r.pointHitRadius,n,s.hitRadius)}}),t._model.skip=o.skip?o.skip:isNaN(t._model.x)||isNaN(t._model.y)},updateBezierControlPoints:function(){var t=this.chart.chartArea,n=this.getMeta();e.each(n.data,function(i,a){var o=i._model,r=e.splineCurve(e.previousItem(n.data,a,!0)._model,o,e.nextItem(n.data,a,!0)._model,o.tension);o.controlPointPreviousX=Math.max(Math.min(r.previous.x,t.right),t.left),o.controlPointPreviousY=Math.max(Math.min(r.previous.y,t.bottom),t.top),o.controlPointNextX=Math.max(Math.min(r.next.x,t.right),t.left),o.controlPointNextY=Math.max(Math.min(r.next.y,t.bottom),t.top),i.pivot()})},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,o=t._model;o.radius=i.hoverRadius?i.hoverRadius:e.getValueAtIndexOrDefault(n.pointHoverRadius,a,this.chart.options.elements.point.hoverRadius),o.backgroundColor=i.hoverBackgroundColor?i.hoverBackgroundColor:e.getValueAtIndexOrDefault(n.pointHoverBackgroundColor,a,e.getHoverColor(o.backgroundColor)),o.borderColor=i.hoverBorderColor?i.hoverBorderColor:e.getValueAtIndexOrDefault(n.pointHoverBorderColor,a,e.getHoverColor(o.borderColor)),o.borderWidth=i.hoverBorderWidth?i.hoverBorderWidth:e.getValueAtIndexOrDefault(n.pointHoverBorderWidth,a,o.borderWidth)},removeHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,o=t._model,r=this.chart.options.elements.point;o.radius=i.radius?i.radius:e.getValueAtIndexOrDefault(n.pointRadius,a,r.radius),o.backgroundColor=i.backgroundColor?i.backgroundColor:e.getValueAtIndexOrDefault(n.pointBackgroundColor,a,r.backgroundColor),o.borderColor=i.borderColor?i.borderColor:e.getValueAtIndexOrDefault(n.pointBorderColor,a,r.borderColor),o.borderWidth=i.borderWidth?i.borderWidth:e.getValueAtIndexOrDefault(n.pointBorderWidth,a,r.borderWidth)}})}},{}],21:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.animation={duration:1e3,easing:"easeOutQuart",onProgress:e.noop,onComplete:e.noop},t.Animation=t.Element.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),t.animationService={frameDuration:17,animations:[],dropFrames:0,request:null,addAnimation:function(t,e,n,i){var a,o,r=this.animations;for(e.chart=t,i||(t.animating=!0),a=0,o=r.length;a1&&(n=Math.floor(t.dropFrames),t.dropFrames=t.dropFrames%1),t.advance(1+n);var i=Date.now();t.dropFrames+=(i-e)/t.frameDuration,t.animations.length>0&&t.requestAnimationFrame()},advance:function(t){for(var n,i,a=this.animations,o=0;o=n.numSteps?(e.callback(n.onAnimationComplete,[n],i),i.animating=!1,a.splice(o,1)):++o}},Object.defineProperty(t.Animation.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(t.Animation.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}})}},{}],22:[function(t,e,n){"use strict";e.exports=function(t){var e=t.canvasHelpers={};e.drawPoint=function(e,n,i,a,o){var r,l,s,u,d,c;if("object"==typeof n&&(r=n.toString(),"[object HTMLImageElement]"===r||"[object HTMLCanvasElement]"===r))return void e.drawImage(n,a-n.width/2,o-n.height/2,n.width,n.height);if(!(isNaN(i)||i<=0)){switch(n){default:e.beginPath(),e.arc(a,o,i,0,2*Math.PI),e.closePath(),e.fill();break;case"triangle":e.beginPath(),l=3*i/Math.sqrt(3),d=l*Math.sqrt(3)/2,e.moveTo(a-l/2,o+d/3),e.lineTo(a+l/2,o+d/3),e.lineTo(a,o-2*d/3),e.closePath(),e.fill();break;case"rect":c=1/Math.SQRT2*i,e.beginPath(),e.fillRect(a-c,o-c,2*c,2*c),e.strokeRect(a-c,o-c,2*c,2*c);break;case"rectRounded":var h=i/Math.SQRT2,f=a-h,g=o-h,p=Math.SQRT2*i;t.helpers.drawRoundedRectangle(e,f,g,p,p,i/2),e.fill();break;case"rectRot":c=1/Math.SQRT2*i,e.beginPath(),e.moveTo(a-c,o),e.lineTo(a,o+c),e.lineTo(a+c,o),e.lineTo(a,o-c),e.closePath(),e.fill();break;case"cross":e.beginPath(),e.moveTo(a,o+i),e.lineTo(a,o-i),e.moveTo(a-i,o),e.lineTo(a+i,o),e.closePath();break;case"crossRot":e.beginPath(),s=Math.cos(Math.PI/4)*i,u=Math.sin(Math.PI/4)*i,e.moveTo(a-s,o-u),e.lineTo(a+s,o+u),e.moveTo(a-s,o+u),e.lineTo(a+s,o-u),e.closePath();break;case"star":e.beginPath(),e.moveTo(a,o+i),e.lineTo(a,o-i),e.moveTo(a-i,o),e.lineTo(a+i,o),s=Math.cos(Math.PI/4)*i,u=Math.sin(Math.PI/4)*i,e.moveTo(a-s,o-u),e.lineTo(a+s,o+u),e.moveTo(a-s,o+u),e.lineTo(a+s,o-u),e.closePath();break;case"line":e.beginPath(),e.moveTo(a-i,o),e.lineTo(a+i,o),e.closePath();break;case"dash":e.beginPath(),e.moveTo(a,o),e.lineTo(a+i,o),e.closePath()}e.stroke()}},e.clipArea=function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},e.unclipArea=function(t){t.restore()},e.lineTo=function(t,e,n,i){return n.steppedLine?("after"===n.steppedLine?t.lineTo(e.x,n.y):t.lineTo(n.x,e.y),void t.lineTo(n.x,n.y)):n.tension?void t.bezierCurveTo(i?e.controlPointPreviousX:e.controlPointNextX,i?e.controlPointPreviousY:e.controlPointNextY,i?n.controlPointNextX:n.controlPointPreviousX,i?n.controlPointNextY:n.controlPointPreviousY,n.x,n.y):void t.lineTo(n.x,n.y)},t.helpers.canvas=e}},{}],23:[function(t,e,n){"use strict";e.exports=function(t){function e(e){e=e||{};var n=e.data=e.data||{};return n.datasets=n.datasets||[],n.labels=n.labels||[],e.options=a.configMerge(t.defaults.global,t.defaults[e.type],e.options||{}),e}function n(t){var e=t.options;e.scale?t.scale.options=e.scale:e.scales&&e.scales.xAxes.concat(e.scales.yAxes).forEach(function(e){t.scales[e.id].options=e}),t.tooltip._options=e.tooltips}function i(t){return"top"===t||"bottom"===t}var a=t.helpers,o=t.plugins,r=t.platform;t.types={},t.instances={},t.controllers={},a.extend(t.prototype,{construct:function(n,i){var o=this;i=e(i);var l=r.acquireContext(n,i),s=l&&l.canvas,u=s&&s.height,d=s&&s.width;return o.id=a.uid(),o.ctx=l,o.canvas=s,o.config=i,o.width=d,o.height=u,o.aspectRatio=u?d/u:null,o.options=i.options,o._bufferedRender=!1,o.chart=o,o.controller=o,t.instances[o.id]=o,Object.defineProperty(o,"data",{get:function(){return o.config.data},set:function(t){o.config.data=t}}),l&&s?(o.initialize(),void o.update()):void console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return o.notify(t,"beforeInit"),a.retinaScale(t),t.bindEvents(),t.options.responsive&&t.resize(!0),t.ensureScalesHaveIDs(),t.buildScales(),t.initToolTip(),o.notify(t,"afterInit"),t},clear:function(){return a.clear(this),this},stop:function(){return t.animationService.cancelAnimation(this),this},resize:function(t){var e=this,n=e.options,i=e.canvas,r=n.maintainAspectRatio&&e.aspectRatio||null,l=Math.floor(a.getMaximumWidth(i)),s=Math.floor(r?l/r:a.getMaximumHeight(i));if((e.width!==l||e.height!==s)&&(i.width=e.width=l,i.height=e.height=s,i.style.width=l+"px",i.style.height=s+"px",a.retinaScale(e),!t)){var u={width:l,height:s};o.notify(e,"resize",[u]),e.options.onResize&&e.options.onResize(e,u),e.stop(),e.update(e.options.responsiveAnimationDuration)}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},n=t.scale;a.each(e.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),a.each(e.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),n&&(n.id=n.id||"scale")},buildScales:function(){var e=this,n=e.options,o=e.scales={},r=[];n.scales&&(r=r.concat((n.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category",dposition:"bottom"}}),(n.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear",dposition:"left"}}))),n.scale&&r.push({options:n.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),a.each(r,function(n){var r=n.options,l=a.getValueOrDefault(r.type,n.dtype),s=t.scaleService.getScaleConstructor(l);if(s){i(r.position)!==i(n.dposition)&&(r.position=n.dposition);var u=new s({id:r.id,options:r,ctx:e.ctx,chart:e});o[u.id]=u,n.isDefault&&(e.scale=u)}}),t.scaleService.addScalesToLayout(this)},buildOrUpdateControllers:function(){var e=this,n=[],i=[];if(a.each(e.data.datasets,function(a,o){var r=e.getDatasetMeta(o);if(r.type||(r.type=a.type||e.config.type),n.push(r.type),r.controller)r.controller.updateIndex(o);else{var l=t.controllers[r.type];if(void 0===l)throw new Error('"'+r.type+'" is not a chart type.');r.controller=new l(e,o),i.push(r.controller)}},e),n.length>1)for(var o=1;o=0;--n)e.isDatasetVisible(n)&&e.drawDataset(n,t);o.notify(e,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var n=this,i=n.getDatasetMeta(t),a={meta:i,index:t,easingValue:e};o.notify(n,"beforeDatasetDraw",[a])!==!1&&(i.controller.draw(e),o.notify(n,"afterDatasetDraw",[a]))},getElementAtEvent:function(e){return t.Interaction.modes.single(this,e)},getElementsAtEvent:function(e){return t.Interaction.modes.label(this,e,{intersect:!0})},getElementsAtXAxis:function(e){return t.Interaction.modes["x-axis"](this,e,{intersect:!0})},getElementsAtEventForMode:function(e,n,i){var a=t.Interaction.modes[n];return"function"==typeof a?a(this,e,i):[]},getDatasetAtEvent:function(e){return t.Interaction.modes.dataset(this,e,{intersect:!0})},getDatasetMeta:function(t){var e=this,n=e.data.datasets[t];n._meta||(n._meta={});var i=n._meta[e.id];return i||(i=n._meta[e.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,n=this.data.datasets.length;e0||(a.forEach(function(e){delete t[e]}),delete t._chartjs)}}var i=t.helpers,a=["push","pop","shift","splice","unshift"];t.DatasetController=function(t,e){this.initialize(t,e)},i.extend(t.DatasetController.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){var n=this;n.chart=t,n.index=e,n.linkScales(),n.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),n=t.getDataset();null===e.xAxisID&&(e.xAxisID=n.xAxisID||t.chart.options.scales.xAxes[0].id),null===e.yAxisID&&(e.yAxisID=n.yAxisID||t.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(t){return this.chart.scales[t]},reset:function(){this.update(!0)},destroy:function(){this._data&&n(this._data,this)},createMetaDataset:function(){var t=this,e=t.datasetElementType;return e&&new e({_chart:t.chart,_datasetIndex:t.index})},createMetaData:function(t){var e=this,n=e.dataElementType;return n&&new n({_chart:e.chart,_datasetIndex:e.index,_index:t})},addElements:function(){var t,e,n=this,i=n.getMeta(),a=n.getDataset().data||[],o=i.data;for(t=0,e=a.length;ti&&t.insertElements(i,a-i)},insertElements:function(t,e){for(var n=0;n=0;a--)e.call(n,t[a],a);else for(a=0;a=i[n].length||!i[n][a].type?i[n].push(o.configMerge(l,e)):e.type&&e.type!==i[n][a].type?i[n][a]=o.configMerge(i[n][a],l,e):i[n][a]=o.configMerge(i[n][a],e)}):(i[n]=[],o.each(e,function(e){var a=o.getValueOrDefault(e.type,"xAxes"===n?"category":"linear");i[n].push(o.configMerge(t.scaleService.getScaleDefaults(a),e))})):i.hasOwnProperty(n)&&"object"==typeof i[n]&&null!==i[n]&&"object"==typeof e?i[n]=o.configMerge(i[n],e):i[n]=e}),i},o.getValueAtIndexOrDefault=function(t,e,n){return void 0===t||null===t?n:o.isArray(t)?e=0;i--){var a=t[i];if(e(a))return a}},o.inherits=function(t){var e=this,n=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},i=function(){this.constructor=n};return i.prototype=e.prototype,n.prototype=new i,n.extend=o.inherits,t&&o.extend(n.prototype,t),n.__super__=e.prototype,n},o.noop=function(){},o.uid=function(){var t=0;return function(){return t++}}(),o.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},o.almostEquals=function(t,e,n){return Math.abs(t-e)t},o.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},o.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},o.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return t=+t,0===t||isNaN(t)?t:t>0?1:-1},o.log10=Math.log10?function(t){return Math.log10(t)}:function(t){return Math.log(t)/Math.LN10},o.toRadians=function(t){return t*(Math.PI/180)},o.toDegrees=function(t){return t*(180/Math.PI)},o.getAngleFromPoint=function(t,e){var n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),o=Math.atan2(i,n);return o<-.5*Math.PI&&(o+=2*Math.PI),{angle:o,distance:a}},o.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},o.aliasPixel=function(t){return t%2===0?0:.5},o.splineCurve=function(t,e,n,i){var a=t.skip?e:t,o=e,r=n.skip?e:n,l=Math.sqrt(Math.pow(o.x-a.x,2)+Math.pow(o.y-a.y,2)),s=Math.sqrt(Math.pow(r.x-o.x,2)+Math.pow(r.y-o.y,2)),u=l/(l+s),d=s/(l+s);u=isNaN(u)?0:u,d=isNaN(d)?0:d;var c=i*u,h=i*d;return{previous:{x:o.x-c*(r.x-a.x),y:o.y-c*(r.y-a.y)},next:{x:o.x+h*(r.x-a.x),y:o.y+h*(r.y-a.y)}}},o.EPSILON=Number.EPSILON||1e-14,o.splineCurveMonotone=function(t){var e,n,i,a,r=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),l=r.length;for(e=0;e0?r[e-1]:null,a=e0?r[e-1]:null,a=e=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},o.previousItem=function(t,e,n){return n?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},o.niceNum=function(t,e){var n,i=Math.floor(o.log10(t)),a=t/Math.pow(10,i);return n=e?a<1.5?1:a<3?2:a<7?5:10:a<=1?1:a<=2?2:a<=5?5:10,n*Math.pow(10,i)};var r=o.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===(t/=1)?1:(n||(n=.3),i0?(n=s[0].clientX,i=s[0].clientY):(n=a.clientX,i=a.clientY);var u=parseFloat(o.getStyle(r,"padding-left")),d=parseFloat(o.getStyle(r,"padding-top")),c=parseFloat(o.getStyle(r,"padding-right")),h=parseFloat(o.getStyle(r,"padding-bottom")),f=l.right-l.left-u-c,g=l.bottom-l.top-d-h;return n=Math.round((n-l.left-u)/f*r.width/e.currentDevicePixelRatio),i=Math.round((i-l.top-d)/g*r.height/e.currentDevicePixelRatio),{x:n,y:i}},o.addEvent=function(t,e,n){t.addEventListener?t.addEventListener(e,n):t.attachEvent?t.attachEvent("on"+e,n):t["on"+e]=n},o.removeEvent=function(t,e,n){t.removeEventListener?t.removeEventListener(e,n,!1):t.detachEvent?t.detachEvent("on"+e,n):t["on"+e]=o.noop},o.getConstraintWidth=function(t){return a(t,"max-width","clientWidth")},o.getConstraintHeight=function(t){return a(t,"max-height","clientHeight")},o.getMaximumWidth=function(t){var e=t.parentNode,n=parseInt(o.getStyle(e,"padding-left"),10),i=parseInt(o.getStyle(e,"padding-right"),10),a=e.clientWidth-n-i,r=o.getConstraintWidth(t);return isNaN(r)?a:Math.min(a,r)},o.getMaximumHeight=function(t){var e=t.parentNode,n=parseInt(o.getStyle(e,"padding-top"),10),i=parseInt(o.getStyle(e,"padding-bottom"),10),a=e.clientHeight-n-i,r=o.getConstraintHeight(t);return isNaN(r)?a:Math.min(a,r)},o.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},o.retinaScale=function(t){var e=t.currentDevicePixelRatio=window.devicePixelRatio||1;if(1!==e){var n=t.canvas,i=t.height,a=t.width;n.height=i*e,n.width=a*e,t.ctx.scale(e,e),n.style.height=i+"px",n.style.width=a+"px"}},o.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},o.fontString=function(t,e,n){return e+" "+t+"px "+n},o.longestText=function(t,e,n,i){i=i||{};var a=i.data=i.data||{},r=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(a=i.data={},r=i.garbageCollect=[],i.font=e),t.font=e;var l=0;o.each(n,function(e){void 0!==e&&null!==e&&o.isArray(e)!==!0?l=o.measureText(t,a,r,l,e):o.isArray(e)&&o.each(e,function(e){void 0===e||null===e||o.isArray(e)||(l=o.measureText(t,a,r,l,e))})});var s=r.length/2;if(s>n.length){for(var u=0;ui&&(i=o),i},o.numberOfLabelLines=function(t){var e=1;return o.each(t,function(t){o.isArray(t)&&t.length>e&&(e=t.length)}),e},o.drawRoundedRectangle=function(t,e,n,i,a,o){t.beginPath(),t.moveTo(e+o,n),t.lineTo(e+i-o,n),t.quadraticCurveTo(e+i,n,e+i,n+o),t.lineTo(e+i,n+a-o),t.quadraticCurveTo(e+i,n+a,e+i-o,n+a),t.lineTo(e+o,n+a),t.quadraticCurveTo(e,n+a,e,n+a-o),t.lineTo(e,n+o),t.quadraticCurveTo(e,n,e+o,n),t.closePath()},o.color=i?function(e){return e instanceof CanvasGradient&&(e=t.defaults.global.defaultColor),i(e)}:function(t){return console.error("Color.js not found!"),t},o.isArray=Array.isArray?function(t){return Array.isArray(t)}:function(t){return"[object Array]"===Object.prototype.toString.call(t)},o.arrayEquals=function(t,e){var n,i,a,r;if(!t||!e||t.length!==e.length)return!1;for(n=0,i=t.length;n0&&(l=t.getDatasetMeta(l[0]._datasetIndex).data),l},"x-axis":function(t,e){return o(t,e,!0)},point:function(t,n){var a=e(n,t);return i(t,a)},nearest:function(t,n,i){var o=e(n,t),r=a(t,o,i.intersect);return r.length>1&&r.sort(function(t,e){var n=t.getArea(),i=e.getArea(),a=n-i;return 0===a&&(a=t._datasetIndex-e._datasetIndex),a}),r.slice(0,1)},x:function(t,i,a){var o=e(i,t),r=[],l=!1;return n(t,function(t){t.inXRange(o.x)&&r.push(t),t.inRange(o.x,o.y)&&(l=!0)}),a.intersect&&!l&&(r=[]),r},y:function(t,i,a){var o=e(i,t),r=[],l=!1;return n(t,function(t){t.inYRange(o.y)&&r.push(t),t.inRange(o.x,o.y)&&(l=!0)}),a.intersect&&!l&&(r=[]),r}}}}},{}],28:[function(t,e,n){"use strict";e.exports=function(){var t=function(t,e){return this.construct(t,e),this};return t.defaults={global:{responsive:!0,responsiveAnimationDuration:0,maintainAspectRatio:!0,events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",showLines:!0,elements:{},legendCallback:function(t){var e=[];e.push('');for(var n=0;n '),t.data.datasets[n].label&&e.push(t.data.datasets[n].label),e.push("");return e.push(" "),e.join("")}}},t.Chart=t,t}},{}],29:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return i.where(t,function(t){return t.position===e})}function n(t,e){t.forEach(function(t,e){return t._tmpIndex_=e,t}),t.sort(function(t,n){var i=e?n:t,a=e?t:n;return i.weight===a.weight?i._tmpIndex_-a._tmpIndex_:i.weight-a.weight}),t.forEach(function(t){delete t._tmpIndex_})}var i=t.helpers;t.layoutService={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,t.boxes.push(e)},removeBox:function(t,e){var n=t.boxes?t.boxes.indexOf(e):-1;n!==-1&&t.boxes.splice(n,1)},configure:function(t,e,n){for(var i,a=["fullWidth","position","weight"],o=a.length,r=0;rc&&rt.maxHeight){r--;break}r++,d=l*u}t.labelRotation=r},afterCalculateTickRotation:function(){i.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){i.callback(this.options.beforeFit,[this])},fit:function(){var t=this,a=t.minSize={width:0,height:0},o=t.options,r=o.ticks,l=o.scaleLabel,s=o.gridLines,u=o.display,d=t.isHorizontal(),c=n(r),h=1.5*n(l).size,f=o.gridLines.tickMarkLength;if(d?a.width=t.isFullWidth()?t.maxWidth-t.margins.left-t.margins.right:t.maxWidth:a.width=u&&s.drawTicks?f:0,d?a.height=u&&s.drawTicks?f:0:a.height=t.maxHeight,l.display&&u&&(d?a.height+=h:a.width+=h),r.display&&u){var g=i.longestText(t.ctx,c.font,t.ticks,t.longestTextCache),p=i.numberOfLabelLines(t.ticks),m=.5*c.size;if(d){t.longestLabelWidth=g;var v=i.toRadians(t.labelRotation),b=Math.cos(v),x=Math.sin(v),y=x*g+c.size*p+m*p;a.height=Math.min(t.maxHeight,a.height+y),t.ctx.font=c.font;var k=t.ticks[0],w=e(t.ctx,k,c.font),M=t.ticks[t.ticks.length-1],S=e(t.ctx,M,c.font);0!==t.labelRotation?(t.paddingLeft="bottom"===o.position?b*w+3:b*m+3,t.paddingRight="bottom"===o.position?b*m+3:b*S+3):(t.paddingLeft=w/2+3,t.paddingRight=S/2+3)}else r.mirror?g=0:g+=t.options.ticks.padding,a.width=Math.min(t.maxWidth,a.width+g),t.paddingTop=c.size/2,t.paddingBottom=c.size/2}t.handleMargins(),t.width=a.width,t.height=a.height},handleMargins:function(){var t=this;t.margins&&(t.paddingLeft=Math.max(t.paddingLeft-t.margins.left,0),t.paddingTop=Math.max(t.paddingTop-t.margins.top,0),t.paddingRight=Math.max(t.paddingRight-t.margins.right,0),t.paddingBottom=Math.max(t.paddingBottom-t.margins.bottom,0))},afterFit:function(){i.callback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){return null===t||"undefined"==typeof t?NaN:"number"!=typeof t||isFinite(t)?"object"==typeof t?t instanceof Date||t.isValid?t:this.getRightValue(this.isHorizontal()?t.x:t.y):t:NaN},getLabelForIndex:i.noop,getPixelForValue:i.noop,getValueForPixel:i.noop,getPixelForTick:function(t,e){var n=this;if(n.isHorizontal()){var i=n.width-(n.paddingLeft+n.paddingRight),a=i/Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),o=a*t+n.paddingLeft;e&&(o+=a/2);var r=n.left+Math.round(o);return r+=n.isFullWidth()?n.margins.left:0}var l=n.height-(n.paddingTop+n.paddingBottom);return n.top+t*(l/(n.ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var n=e.width-(e.paddingLeft+e.paddingRight),i=n*t+e.paddingLeft,a=e.left+Math.round(i);return a+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this,e=t.min,n=t.max;return t.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0},draw:function(e){var a=this,o=a.options;if(o.display){var r,l,s=a.ctx,u=t.defaults.global,d=o.ticks,c=o.gridLines,h=o.scaleLabel,f=0!==a.labelRotation,g=d.autoSkip,p=a.isHorizontal();d.maxTicksLimit&&(l=d.maxTicksLimit);var m=i.getValueOrDefault(d.fontColor,u.defaultFontColor),v=n(d),b=c.drawTicks?c.tickMarkLength:0,x=i.getValueOrDefault(h.fontColor,u.defaultFontColor),y=n(h),k=i.toRadians(a.labelRotation),w=Math.cos(k),M=a.longestLabelWidth*w;s.fillStyle=m;var S=[];if(p){if(r=!1,(M+d.autoSkipPadding)*a.ticks.length>a.width-(a.paddingLeft+a.paddingRight)&&(r=1+Math.floor((M+d.autoSkipPadding)*a.ticks.length/(a.width-(a.paddingLeft+a.paddingRight)))),l&&a.ticks.length>l)for(;!r||a.ticks.length/(r||1)>l;)r||(r=1),r+=1;g||(r=!1)}var C="right"===o.position?a.left:a.right-b,D="right"===o.position?a.left+b:a.right,I="bottom"===o.position?a.top:a.bottom-b,A="bottom"===o.position?a.top+b:a.bottom;if(i.each(a.ticks,function(t,n){if(void 0!==t&&null!==t){var l=a.ticks.length===n+1,s=r>1&&n%r>0||n%r===0&&n+r>=a.ticks.length;if((!s||l)&&void 0!==t&&null!==t){var h,g,m,v;n===("undefined"!=typeof a.zeroLineIndex?a.zeroLineIndex:0)?(h=c.zeroLineWidth,g=c.zeroLineColor,m=c.zeroLineBorderDash,v=c.zeroLineBorderDashOffset):(h=i.getValueAtIndexOrDefault(c.lineWidth,n),g=i.getValueAtIndexOrDefault(c.color,n),m=i.getValueOrDefault(c.borderDash,u.borderDash),v=i.getValueOrDefault(c.borderDashOffset,u.borderDashOffset));var x,y,w,M,P,_,T,F,R,L,V="middle",O="middle";if(p){"bottom"===o.position?(O=f?"middle":"top",V=f?"right":"center",L=a.top+b):(O=f?"middle":"bottom",V=f?"left":"center",L=a.bottom-b);var z=a.getPixelForTick(n)+i.aliasPixel(h);R=a.getPixelForTick(n,c.offsetGridLines)+d.labelOffset,x=w=P=T=z,y=I,M=A,_=e.top,F=e.bottom}else{var B,W="left"===o.position,N=d.padding;d.mirror?(V=W?"left":"right",B=N):(V=W?"right":"left",
+B=b+N),R=W?a.right-B:a.left+B;var E=a.getPixelForTick(n);E+=i.aliasPixel(h),L=a.getPixelForTick(n,c.offsetGridLines),x=C,w=D,P=e.left,T=e.right,y=M=_=F=E}S.push({tx1:x,ty1:y,tx2:w,ty2:M,x1:P,y1:_,x2:T,y2:F,labelX:R,labelY:L,glWidth:h,glColor:g,glBorderDash:m,glBorderDashOffset:v,rotation:-1*k,label:t,textBaseline:O,textAlign:V})}}}),i.each(S,function(t){if(c.display&&(s.save(),s.lineWidth=t.glWidth,s.strokeStyle=t.glColor,s.setLineDash&&(s.setLineDash(t.glBorderDash),s.lineDashOffset=t.glBorderDashOffset),s.beginPath(),c.drawTicks&&(s.moveTo(t.tx1,t.ty1),s.lineTo(t.tx2,t.ty2)),c.drawOnChartArea&&(s.moveTo(t.x1,t.y1),s.lineTo(t.x2,t.y2)),s.stroke(),s.restore()),d.display){s.save(),s.translate(t.labelX,t.labelY),s.rotate(t.rotation),s.font=v.font,s.textBaseline=t.textBaseline,s.textAlign=t.textAlign;var e=t.label;if(i.isArray(e))for(var n=0,a=0;n0)i=t.stepSize;else{var o=e.niceNum(n.max-n.min,!1);i=e.niceNum(o/(t.maxTicks-1),!0)}var r=Math.floor(n.min/i)*i,l=Math.ceil(n.max/i)*i;t.min&&t.max&&t.stepSize&&e.almostWhole((t.max-t.min)/t.stepSize,i/1e3)&&(r=t.min,l=t.max);var s=(l-r)/i;s=e.almostEquals(s,Math.round(s),i/1e3)?Math.round(s):Math.ceil(s),a.push(void 0!==t.min?t.min:r);for(var u=1;u3?i[2]-i[1]:i[1]-i[0];Math.abs(a)>1&&t!==Math.floor(t)&&(a=t-Math.floor(t));var o=e.log10(Math.abs(a)),r="";if(0!==t){var l=-1*Math.floor(o);l=Math.max(Math.min(l,20),0),r=t.toFixed(l)}else r="0";return r},logarithmic:function(t,n,i){var a=t/Math.pow(10,Math.floor(e.log10(t)));return 0===t?"0":1===a||2===a||5===a||0===n||n===i.length-1?t.toExponential():""}}}}},{}],34:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){var n=s.color(t);return n.alpha(e*n.alpha()).rgbaString()}function n(t,e){return e&&(s.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function i(t){var e=t._xScale,n=t._yScale||t._scale,i=t._index,a=t._datasetIndex;return{xLabel:e?e.getLabelForIndex(i,a):"",yLabel:n?n.getLabelForIndex(i,a):"",index:i,datasetIndex:a,x:t._model.x,y:t._model.y}}function a(e){var n=t.defaults.global,i=s.getValueOrDefault;return{xPadding:e.xPadding,yPadding:e.yPadding,xAlign:e.xAlign,yAlign:e.yAlign,bodyFontColor:e.bodyFontColor,_bodyFontFamily:i(e.bodyFontFamily,n.defaultFontFamily),_bodyFontStyle:i(e.bodyFontStyle,n.defaultFontStyle),_bodyAlign:e.bodyAlign,bodyFontSize:i(e.bodyFontSize,n.defaultFontSize),bodySpacing:e.bodySpacing,titleFontColor:e.titleFontColor,_titleFontFamily:i(e.titleFontFamily,n.defaultFontFamily),_titleFontStyle:i(e.titleFontStyle,n.defaultFontStyle),titleFontSize:i(e.titleFontSize,n.defaultFontSize),_titleAlign:e.titleAlign,titleSpacing:e.titleSpacing,titleMarginBottom:e.titleMarginBottom,footerFontColor:e.footerFontColor,_footerFontFamily:i(e.footerFontFamily,n.defaultFontFamily),_footerFontStyle:i(e.footerFontStyle,n.defaultFontStyle),footerFontSize:i(e.footerFontSize,n.defaultFontSize),_footerAlign:e.footerAlign,footerSpacing:e.footerSpacing,footerMarginTop:e.footerMarginTop,caretSize:e.caretSize,cornerRadius:e.cornerRadius,backgroundColor:e.backgroundColor,opacity:0,legendColorBackground:e.multiKeyBackground,displayColors:e.displayColors,borderColor:e.borderColor,borderWidth:e.borderWidth}}function o(t,e){var n=t._chart.ctx,i=2*e.yPadding,a=0,o=e.body,r=o.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);r+=e.beforeBody.length+e.afterBody.length;var l=e.title.length,u=e.footer.length,d=e.titleFontSize,c=e.bodyFontSize,h=e.footerFontSize;i+=l*d,i+=l?(l-1)*e.titleSpacing:0,i+=l?e.titleMarginBottom:0,i+=r*c,i+=r?(r-1)*e.bodySpacing:0,i+=u?e.footerMarginTop:0,i+=u*h,i+=u?(u-1)*e.footerSpacing:0;var f=0,g=function(t){a=Math.max(a,n.measureText(t).width+f)};return n.font=s.fontString(d,e._titleFontStyle,e._titleFontFamily),s.each(e.title,g),n.font=s.fontString(c,e._bodyFontStyle,e._bodyFontFamily),s.each(e.beforeBody.concat(e.afterBody),g),f=e.displayColors?c+2:0,s.each(o,function(t){s.each(t.before,g),s.each(t.lines,g),s.each(t.after,g)}),f=0,n.font=s.fontString(h,e._footerFontStyle,e._footerFontFamily),s.each(e.footer,g),a+=2*e.xPadding,{width:a,height:i}}function r(t,e){var n=t._model,i=t._chart,a=t._chart.chartArea,o="center",r="center";n.yi.height-e.height&&(r="bottom");var l,s,u,d,c,h=(a.left+a.right)/2,f=(a.top+a.bottom)/2;"center"===r?(l=function(t){return t<=h},s=function(t){return t>h}):(l=function(t){return t<=e.width/2},s=function(t){return t>=i.width-e.width/2}),u=function(t){return t+e.width>i.width},d=function(t){return t-e.width<0},c=function(t){return t<=f?"top":"bottom"},l(n.x)?(o="left",u(n.x)&&(o="center",r=c(n.y))):s(n.x)&&(o="right",d(n.x)&&(o="center",r=c(n.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:o,yAlign:g.yAlign?g.yAlign:r}}function l(t,e,n){var i=t.x,a=t.y,o=t.caretSize,r=t.caretPadding,l=t.cornerRadius,s=n.xAlign,u=n.yAlign,d=o+r,c=l+r;return"right"===s?i-=e.width:"center"===s&&(i-=e.width/2),"top"===u?a+=d:a-="bottom"===u?e.height+d:e.height/2,"center"===u?"left"===s?i+=d:"right"===s&&(i-=d):"left"===s?i-=c:"right"===s&&(i+=c),{x:i,y:a}}var s=t.helpers;t.defaults.global.tooltips={enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:s.noop,title:function(t,e){var n="",i=e.labels,a=i?i.length:0;if(t.length>0){var o=t[0];o.xLabel?n=o.xLabel:a>0&&o.index0&&i.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n={width:e.width,height:e.height},i={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,o=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&o&&(this.drawBackground(i,e,t,n,a),i.x+=e.xPadding,i.y+=e.yPadding,this.drawTitle(i,e,t,a),this.drawBody(i,e,t,a),this.drawFooter(i,e,t,a))}},handleEvent:function(t){var e=this,n=e._options,i=!1;if(e._lastActive=e._lastActive||[],"mouseout"===t.type?e._active=[]:e._active=e._chart.getElementsAtEventForMode(t,n.mode,n),i=!s.arrayEquals(e._active,e._lastActive),!i)return!1;if(e._lastActive=e._active,n.enabled||n.custom){e._eventPosition={x:t.x,y:t.y};var a=e._model;e.update(!0),e.pivot(),i|=a.x!==e._model.x||a.y!==e._model.y}return i}}),t.Tooltip.positioners={average:function(t){if(!t.length)return!1;var e,n,i=0,a=0,o=0;for(e=0,n=t.length;es;)o-=2*Math.PI;for(;o=l&&o<=s,d=r>=i.innerRadius&&r<=i.outerRadius;return u&&d}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,n=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,n=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},draw:function(){var t=this._chart.ctx,e=this._view,n=e.startAngle,i=e.endAngle;t.beginPath(),t.arc(e.x,e.y,e.outerRadius,n,i),t.arc(e.x,e.y,e.innerRadius,i,n,!0),t.closePath(),t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.fillStyle=e.backgroundColor,t.fill(),t.lineJoin="bevel",e.borderWidth&&t.stroke()}})}},{}],36:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global;t.defaults.global.elements.line={tension:.4,backgroundColor:n.defaultColor,borderWidth:3,borderColor:n.defaultColor,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0},t.elements.Line=t.Element.extend({draw:function(){var t,i,a,o,r=this,l=r._view,s=r._chart.ctx,u=l.spanGaps,d=r._children.slice(),c=n.elements.line,h=-1;for(r._loop&&d.length&&d.push(d[0]),s.save(),s.lineCap=l.borderCapStyle||c.borderCapStyle,s.setLineDash&&s.setLineDash(l.borderDash||c.borderDash),s.lineDashOffset=l.borderDashOffset||c.borderDashOffset,s.lineJoin=l.borderJoinStyle||c.borderJoinStyle,s.lineWidth=l.borderWidth||c.borderWidth,s.strokeStyle=l.borderColor||n.defaultColor,s.beginPath(),h=-1,t=0;te?1:-1,r=1,l=u.borderSkipped||"left"):(e=u.x-u.width/2,n=u.x+u.width/2,i=u.y,a=u.base,o=1,r=a>i?1:-1,l=u.borderSkipped||"bottom"),d){var c=Math.min(Math.abs(e-n),Math.abs(i-a));d=d>c?c:d;var h=d/2,f=e+("left"!==l?h*o:0),g=n+("right"!==l?-h*o:0),p=i+("top"!==l?h*r:0),m=a+("bottom"!==l?-h*r:0);f!==g&&(i=p,a=m),p!==m&&(e=f,n=g)}s.beginPath(),s.fillStyle=u.backgroundColor,s.strokeStyle=u.borderColor,s.lineWidth=d;var v=[[e,a],[e,i],[n,i],[n,a]],b=["bottom","left","top","right"],x=b.indexOf(l,0);x===-1&&(x=0);var y=t(0);s.moveTo(y[0],y[1]);for(var k=1;k<4;k++)y=t(k),s.lineTo(y[0],y[1]);s.fill(),d&&s.stroke()},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){var i=!1;if(this._view){var a=n(this);i=t>=a.left&&t<=a.right&&e>=a.top&&e<=a.bottom}return i},inLabelRange:function(t,i){var a=this;if(!a._view)return!1;var o=!1,r=n(a);return o=e(a)?t>=r.left&&t<=r.right:i>=r.top&&i<=r.bottom},inXRange:function(t){var e=n(this);return t>=e.left&&t<=e.right},inYRange:function(t){var e=n(this);return t>=e.top&&t<=e.bottom},getCenterPoint:function(){var t,n,i=this._view;return e(this)?(t=i.x,n=(i.y+i.base)/2):(t=(i.x+i.base)/2,n=i.y),{x:t,y:n}},getArea:function(){var t=this._view;return t.width*Math.abs(t.y-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}})}},{}],39:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){var n=s.getStyle(t,e),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?Number(i[1]):void 0}function n(t,n){var i=t.style,a=t.getAttribute("height"),o=t.getAttribute("width");if(t._chartjs={initial:{height:a,width:o,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",null===o||""===o){var r=e(t,"width");void 0!==r&&(t.width=r)}if(null===a||""===a)if(""===t.style.height)t.height=t.width/(n.options.aspectRatio||2);else{var l=e(t,"height");void 0!==r&&(t.height=l)}return t}function i(t,e,n,i,a){return{type:t,chart:e,native:a||null,x:void 0!==n?n:null,y:void 0!==i?i:null}}function a(t,e){var n=u[t.type]||t.type,a=s.getRelativePosition(t,e);return i(n,e,a.x,a.y,t)}function o(t){var e=document.createElement("iframe");return e.className="chartjs-hidden-iframe",e.style.cssText="display:block;overflow:hidden;border:0;margin:0;top:0;left:0;bottom:0;right:0;height:100%;width:100%;position:absolute;pointer-events:none;z-index:-1;",e.tabIndex=-1,s.addEvent(e,"load",function(){s.addEvent(e.contentWindow||e,"resize",t),t()}),e}function r(t,e,n){var a=t._chartjs={ticking:!1},r=function(){a.ticking||(a.ticking=!0,s.requestAnimFrame.call(window,function(){if(a.resizer)return a.ticking=!1,e(i("resize",n))}))};a.resizer=o(r),t.insertBefore(a.resizer,t.firstChild)}function l(t){if(t&&t._chartjs){var e=t._chartjs.resizer;e&&(e.parentNode.removeChild(e),t._chartjs.resizer=null),delete t._chartjs}}var s=t.helpers,u={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};return{acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(n(t,e),i):null},releaseContext:function(t){var e=t.canvas;if(e._chartjs){var n=e._chartjs.initial;["height","width"].forEach(function(t){var i=n[t];void 0===i||null===i?e.removeAttribute(t):e.setAttribute(t,i)}),s.each(n.style||{},function(t,n){e.style[n]=t}),e.width=e.width,delete e._chartjs}},addEventListener:function(t,e,n){var i=t.canvas;if("resize"===e)return void r(i.parentNode,n,t);var o=n._chartjs||(n._chartjs={}),l=o.proxies||(o.proxies={}),u=l[t.id+"_"+e]=function(e){n(a(e,t))};s.addEvent(i,e,u)},removeEventListener:function(t,e,n){var i=t.canvas;if("resize"===e)return void l(i.parentNode,n);var a=n._chartjs||{},o=a.proxies||{},r=o[t.id+"_"+e];r&&s.removeEvent(i,e,r)}}}},{}],40:[function(t,e,n){"use strict";var i=t(39);e.exports=function(t){t.platform={acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},t.helpers.extend(t.platform,i(t))}},{39:39}],41:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e,n){var i,a=t._model||{},o=a.fill;if(void 0===o&&(o=!!a.backgroundColor),o===!1||null===o)return!1;if(o===!0)return"origin";if(i=parseFloat(o,10),isFinite(i)&&Math.floor(i)===i)return"-"!==o[0]&&"+"!==o[0]||(i=e+i),!(i===e||i<0||i>=n)&&i;switch(o){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return o;default:return!1}}function n(t){var e,n=t.el._model||{},i=t.el._scale||{},a=t.fill,o=null;if(isFinite(a))return null;if("start"===a?o=void 0===n.scaleBottom?i.bottom:n.scaleBottom:"end"===a?o=void 0===n.scaleTop?i.top:n.scaleTop:void 0!==n.scaleZero?o=n.scaleZero:i.getBasePosition?o=i.getBasePosition():i.getBasePixel&&(o=i.getBasePixel()),void 0!==o&&null!==o){if(void 0!==o.x&&void 0!==o.y)return o;if("number"==typeof o&&isFinite(o))return e=i.isHorizontal(),{x:e?o:null,y:e?null:o}}return null}function i(t,e,n){var i,a=t[e],o=a.fill,r=[e];if(!n)return o;for(;o!==!1&&r.indexOf(o)===-1;){if(!isFinite(o))return o;if(i=t[o],!i)return!1;if(i.visible)return o;r.push(o),o=i.fill}return!1}function a(t){var e=t.fill,n="dataset";return e===!1?null:(isFinite(e)||(n="boundary"),d[n](t))}function o(t){return t&&!t.skip}function r(t,e,n,i,a){var o;if(i&&a){for(t.moveTo(e[0].x,e[0].y),o=1;o0;--o)u.canvas.lineTo(t,n[o],n[o-1],!0)}}function l(t,e,n,i,a,l){var s,u,d,c,h,f,g,p=e.length,m=i.spanGaps,v=[],b=[],x=0,y=0;for(t.beginPath(),s=0,u=p+!!l;s=n.width&&(b+=d+o.padding,v[v.length]=n.left),g[i]={left:0,top:0,width:r,height:d},v[v.length-1]+=r+o.padding}),p.height+=b}else{var x=o.padding,y=n.columnWidths=[],k=o.padding,w=0,M=0,S=d+x;i.each(n.legendItems,function(t,n){var i=e(o,d),a=i+d/2+l.measureText(t.text).width;M+S>p.height&&(k+=w+o.padding,y.push(w),w=0,M=0),w=Math.max(w,a),M+=S,g[n]={left:0,top:0,width:a,height:d}}),k+=w,y.push(w),p.width+=k}n.width=p.width,n.height=p.height},afterFit:o,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var n=this,a=n.options,o=a.labels,r=t.defaults.global,l=r.elements.line,s=n.width,u=n.lineWidths;if(a.display){var d,c=n.ctx,h=i.getValueOrDefault,f=h(o.fontColor,r.defaultFontColor),g=h(o.fontSize,r.defaultFontSize),p=h(o.fontStyle,r.defaultFontStyle),m=h(o.fontFamily,r.defaultFontFamily),v=i.fontString(g,p,m);c.textAlign="left",c.textBaseline="top",c.lineWidth=.5,c.strokeStyle=f,c.fillStyle=f,c.font=v;var b=e(o,g),x=n.legendHitBoxes,y=function(e,n,i){if(!(isNaN(b)||b<=0)){c.save(),c.fillStyle=h(i.fillStyle,r.defaultColor),c.lineCap=h(i.lineCap,l.borderCapStyle),c.lineDashOffset=h(i.lineDashOffset,l.borderDashOffset),c.lineJoin=h(i.lineJoin,l.borderJoinStyle),c.lineWidth=h(i.lineWidth,l.borderWidth),c.strokeStyle=h(i.strokeStyle,r.defaultColor);var o=0===h(i.lineWidth,l.borderWidth);if(c.setLineDash&&c.setLineDash(h(i.lineDash,l.borderDash)),a.labels&&a.labels.usePointStyle){var s=g*Math.SQRT2/2,u=s/Math.SQRT2,d=e+u,f=n+u;t.canvasHelpers.drawPoint(c,i.pointStyle,s,d,f)}else o||c.strokeRect(e,n,b,g),c.fillRect(e,n,b,g);c.restore()}},k=function(t,e,n,i){c.fillText(n.text,b+g/2+t,e),n.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(b+g/2+t,e+g/2),c.lineTo(b+g/2+t+i,e+g/2),c.stroke())},w=n.isHorizontal();d=w?{x:n.left+(s-u[0])/2,y:n.top+o.padding,line:0}:{x:n.left+o.padding,y:n.top+o.padding,line:0};var M=g+o.padding;i.each(n.legendItems,function(t,e){var i=c.measureText(t.text).width,a=b+g/2+i,r=d.x,l=d.y;w?r+a>=s&&(l=d.y+=M,d.line++,r=d.x=n.left+(s-u[d.line])/2):l+M>n.bottom&&(r=d.x=r+n.columnWidths[d.line]+o.padding,l=d.y=n.top+o.padding,d.line++),y(r,l,t),x[e].left=r,x[e].top=l,k(r,l,t,i),w?d.x+=a+o.padding:d.y+=M})}},handleEvent:function(t){var e=this,n=e.options,i="mouseup"===t.type?"click":t.type,a=!1;if("mousemove"===i){if(!n.onHover)return}else{if("click"!==i)return;if(!n.onClick)return}var o=t.x,r=t.y;if(o>=e.left&&o<=e.right&&r>=e.top&&r<=e.bottom)for(var l=e.legendHitBoxes,s=0;s=u.left&&o<=u.left+u.width&&r>=u.top&&r<=u.top+u.height){if("click"===i){n.onClick.call(e,t.native,e.legendItems[s]),a=!0;break}if("mousemove"===i){n.onHover.call(e,t.native,e.legendItems[s]),a=!0;break}}}return a}}),{id:"legend",beforeInit:function(t){var e=t.options.legend;e&&n(t,e)},beforeUpdate:function(e){var o=e.options.legend,r=e.legend;o?(o=i.configMerge(t.defaults.global.legend,o),r?(a.configure(e,r,o),r.options=o):n(e,o)):r&&(a.removeBox(e,r),delete e.legend)},afterEvent:function(t,e){var n=t.legend;n&&n.handleEvent(e)}}}},{}],43:[function(t,e,n){"use strict";e.exports=function(t){function e(e,n){var a=new t.Title({ctx:e.ctx,options:n,chart:e});i.configure(e,a,n),i.addBox(e,a),e.titleBlock=a}var n=t.helpers,i=t.layoutService,a=n.noop;return t.defaults.global.title={display:!1,position:"top",fullWidth:!0,weight:2e3,fontStyle:"bold",padding:10,text:""},t.Title=t.Element.extend({initialize:function(t){var e=this;n.extend(e,t),e.legendHitBoxes=[];
+},beforeUpdate:a,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:a,beforeSetDimensions:a,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:a,beforeBuildLabels:a,buildLabels:a,afterBuildLabels:a,beforeFit:a,fit:function(){var e=this,i=n.getValueOrDefault,a=e.options,o=t.defaults.global,r=a.display,l=i(a.fontSize,o.defaultFontSize),s=e.minSize;e.isHorizontal()?(s.width=e.maxWidth,s.height=r?l+2*a.padding:0):(s.width=r?l+2*a.padding:0,s.height=e.maxHeight),e.width=s.width,e.height=s.height},afterFit:a,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var e=this,i=e.ctx,a=n.getValueOrDefault,o=e.options,r=t.defaults.global;if(o.display){var l,s,u,d=a(o.fontSize,r.defaultFontSize),c=a(o.fontStyle,r.defaultFontStyle),h=a(o.fontFamily,r.defaultFontFamily),f=n.fontString(d,c,h),g=0,p=e.top,m=e.left,v=e.bottom,b=e.right;i.fillStyle=a(o.fontColor,r.defaultFontColor),i.font=f,e.isHorizontal()?(l=m+(b-m)/2,s=p+(v-p)/2,u=b-m):(l="left"===o.position?m+d/2:b-d/2,s=p+(v-p)/2,u=v-p,g=Math.PI*("left"===o.position?-.5:.5)),i.save(),i.translate(l,s),i.rotate(g),i.textAlign="center",i.textBaseline="middle",i.fillText(o.text,0,0,u),i.restore()}}}),{id:"title",beforeInit:function(t){var n=t.options.title;n&&e(t,n)},beforeUpdate:function(a){var o=a.options.title,r=a.titleBlock;o?(o=n.configMerge(t.defaults.global.title,o),r?(i.configure(a,r,o),r.options=o):e(a,o)):r&&(t.layoutService.removeBox(a,r),delete a.titleBlock)}}}},{}],44:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"bottom"},i=t.Scale.extend({getLabels:function(){var t=this.chart.data;return(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t=this,n=t.getLabels();t.minIndex=0,t.maxIndex=n.length-1;var i;void 0!==t.options.ticks.min&&(i=e.indexOf(n,t.options.ticks.min),t.minIndex=i!==-1?i:t.minIndex),void 0!==t.options.ticks.max&&(i=e.indexOf(n,t.options.ticks.max),t.maxIndex=i!==-1?i:t.maxIndex),t.min=n[t.minIndex],t.max=n[t.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var n=this,i=n.chart.data,a=n.isHorizontal();return i.yLabels&&!a?n.getRightValue(i.datasets[e].data[t]):n.ticks[t-n.minIndex]},getPixelForValue:function(t,e,n,i){var a,o=this,r=Math.max(o.maxIndex+1-o.minIndex-(o.options.gridLines.offsetGridLines?0:1),1);if(void 0!==t&&null!==t&&(a=o.isHorizontal()?t.x:t.y),void 0!==a||void 0!==t&&isNaN(e)){var l=o.getLabels();t=a||t;var s=l.indexOf(t);e=s!==-1?s:e}if(o.isHorizontal()){var u=o.width/r,d=u*(e-o.minIndex);return(o.options.gridLines.offsetGridLines&&i||o.maxIndex===o.minIndex&&i)&&(d+=u/2),o.left+Math.round(d)}var c=o.height/r,h=c*(e-o.minIndex);return o.options.gridLines.offsetGridLines&&i&&(h+=c/2),o.top+Math.round(h)},getPixelForTick:function(t,e){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null,e)},getValueForPixel:function(t){var e,n=this,i=Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),a=n.isHorizontal(),o=(a?n.width:n.height)/i;return t-=a?n.left:n.top,n.options.gridLines.offsetGridLines&&(t-=o/2),e=t<=0?0:Math.round(t/o)},getBasePixel:function(){return this.bottom}});t.scaleService.registerScaleType("category",i,n)}},{}],45:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:t.Ticks.formatters.linear}},i=t.LinearScaleBase.extend({determineDataLimits:function(){function t(t){return l?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=n.chart,o=a.data,r=o.datasets,l=n.isHorizontal(),s=0,u=1;n.min=null,n.max=null;var d=i.stacked;if(void 0===d&&e.each(r,function(e,n){if(!d){var i=a.getDatasetMeta(n);a.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(d=!0)}}),i.stacked||d){var c={};e.each(r,function(o,r){var l=a.getDatasetMeta(r),s=[l.type,void 0===i.stacked&&void 0===l.stack?r:"",l.stack].join(".");void 0===c[s]&&(c[s]={positiveValues:[],negativeValues:[]});var u=c[s].positiveValues,d=c[s].negativeValues;a.isDatasetVisible(r)&&t(l)&&e.each(o.data,function(t,e){var a=+n.getRightValue(t);isNaN(a)||l.data[e].hidden||(u[e]=u[e]||0,d[e]=d[e]||0,i.relativePoints?u[e]=100:a<0?d[e]+=a:u[e]+=a)})}),e.each(c,function(t){var i=t.positiveValues.concat(t.negativeValues),a=e.min(i),o=e.max(i);n.min=null===n.min?a:Math.min(n.min,a),n.max=null===n.max?o:Math.max(n.max,o)})}else e.each(r,function(i,o){var r=a.getDatasetMeta(o);a.isDatasetVisible(o)&&t(r)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||r.data[e].hidden||(null===n.min?n.min=i:in.max&&(n.max=i))})});n.min=isFinite(n.min)?n.min:s,n.max=isFinite(n.max)?n.max:u,this.handleTickRangeOptions()},getTickLimit:function(){var n,i=this,a=i.options.ticks;if(i.isHorizontal())n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.width/50));else{var o=e.getValueOrDefault(a.fontSize,t.defaults.global.defaultFontSize);n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.height/(2*o)))}return n},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e,n=this,i=n.start,a=+n.getRightValue(t),o=n.end-i;return n.isHorizontal()?(e=n.left+n.width/o*(a-i),Math.round(e)):(e=n.bottom-n.height/o*(a-i),Math.round(e))},getValueForPixel:function(t){var e=this,n=e.isHorizontal(),i=n?e.width:e.height,a=(n?t-e.left:e.bottom-t)/i;return e.start+(e.end-e.start)*a},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}});t.scaleService.registerScaleType("linear",i,n)}},{}],46:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=e.noop;t.LinearScaleBase=t.Scale.extend({handleTickRangeOptions:function(){var t=this,n=t.options,i=n.ticks;if(i.beginAtZero){var a=e.sign(t.min),o=e.sign(t.max);a<0&&o<0?t.max=0:a>0&&o>0&&(t.min=0)}void 0!==i.min?t.min=i.min:void 0!==i.suggestedMin&&(null===t.min?t.min=i.suggestedMin:t.min=Math.min(t.min,i.suggestedMin)),void 0!==i.max?t.max=i.max:void 0!==i.suggestedMax&&(null===t.max?t.max=i.suggestedMax:t.max=Math.max(t.max,i.suggestedMax)),t.min===t.max&&(t.max++,i.beginAtZero||t.min--)},getTickLimit:n,handleDirectionalChanges:n,buildTicks:function(){var n=this,i=n.options,a=i.ticks,o=n.getTickLimit();o=Math.max(2,o);var r={maxTicks:o,min:a.min,max:a.max,stepSize:e.getValueOrDefault(a.fixedStepSize,a.stepSize)},l=n.ticks=t.Ticks.generators.linear(r,n);n.handleDirectionalChanges(),n.max=e.max(l),n.min=e.min(l),a.reverse?(l.reverse(),n.start=n.max,n.end=n.min):(n.start=n.min,n.end=n.max)},convertTicksToLabels:function(){var e=this;e.ticksAsNumbers=e.ticks.slice(),e.zeroLineIndex=e.ticks.indexOf(0),t.Scale.prototype.convertTicksToLabels.call(e)}})}},{}],47:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:t.Ticks.formatters.logarithmic}},i=t.Scale.extend({determineDataLimits:function(){function t(t){return u?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=i.ticks,o=n.chart,r=o.data,l=r.datasets,s=e.getValueOrDefault,u=n.isHorizontal();n.min=null,n.max=null,n.minNotZero=null;var d=i.stacked;if(void 0===d&&e.each(l,function(e,n){if(!d){var i=o.getDatasetMeta(n);o.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(d=!0)}}),i.stacked||d){var c={};e.each(l,function(a,r){var l=o.getDatasetMeta(r),s=[l.type,void 0===i.stacked&&void 0===l.stack?r:"",l.stack].join(".");o.isDatasetVisible(r)&&t(l)&&(void 0===c[s]&&(c[s]=[]),e.each(a.data,function(t,e){var a=c[s],o=+n.getRightValue(t);isNaN(o)||l.data[e].hidden||(a[e]=a[e]||0,i.relativePoints?a[e]=100:a[e]+=o)}))}),e.each(c,function(t){var i=e.min(t),a=e.max(t);n.min=null===n.min?i:Math.min(n.min,i),n.max=null===n.max?a:Math.max(n.max,a)})}else e.each(l,function(i,a){var r=o.getDatasetMeta(a);o.isDatasetVisible(a)&&t(r)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||r.data[e].hidden||(null===n.min?n.min=i:in.max&&(n.max=i),0!==i&&(null===n.minNotZero||ia?{start:e-n-5,end:e}:{start:e,end:e+n+5}}function o(t){var o,r,l,s=n(t),u=Math.min(t.height/2,t.width/2),d={r:t.width,l:0,t:t.height,b:0},c={};t.ctx.font=s.font,t._pointLabelSizes=[];var h=e(t);for(o=0;od.r&&(d.r=m.end,c.r=g),v.startd.b&&(d.b=v.end,c.b=g)}t.setReductions(u,d,c)}function r(t){var e=Math.min(t.height/2,t.width/2);t.drawingArea=Math.round(e),t.setCenterPoint(0,0,0,0)}function l(t){return 0===t||180===t?"center":t<180?"left":"right"}function s(t,e,n,i){if(f.isArray(e))for(var a=n.y,o=1.5*i,r=0;r270||t<90)&&(n.y-=e.h)}function d(t){var i=t.ctx,a=f.getValueOrDefault,o=t.options,r=o.angleLines,d=o.pointLabels;i.lineWidth=r.lineWidth,i.strokeStyle=r.color;var c=t.getDistanceFromCenterForValue(o.reverse?t.min:t.max),h=n(t);i.textBaseline="top";for(var p=e(t)-1;p>=0;p--){if(r.display){var m=t.getPointPosition(p,c);i.beginPath(),i.moveTo(t.xCenter,t.yCenter),i.lineTo(m.x,m.y),i.stroke(),i.closePath()}if(d.display){var v=t.getPointPosition(p,c+5),b=a(d.fontColor,g.defaultFontColor);i.font=h.font,i.fillStyle=b;var x=t.getIndexAngle(p),y=f.toDegrees(x);i.textAlign=l(y),u(y,t._pointLabelSizes[p],v),s(i,t.pointLabels[p]||"",v,h.size)}}}function c(t,n,i,a){var o=t.ctx;if(o.strokeStyle=f.getValueAtIndexOrDefault(n.color,a-1),o.lineWidth=f.getValueAtIndexOrDefault(n.lineWidth,a-1),t.options.gridLines.circular)o.beginPath(),o.arc(t.xCenter,t.yCenter,i,0,2*Math.PI),o.closePath(),o.stroke();else{var r=e(t);if(0===r)return;o.beginPath();var l=t.getPointPosition(0,i);o.moveTo(l.x,l.y);for(var s=1;s0&&n>0?e:0)},draw:function(){var t=this,e=t.options,n=e.gridLines,i=e.ticks,a=f.getValueOrDefault;if(e.display){var o=t.ctx,r=a(i.fontSize,g.defaultFontSize),l=a(i.fontStyle,g.defaultFontStyle),s=a(i.fontFamily,g.defaultFontFamily),u=f.fontString(r,l,s);f.each(t.ticks,function(l,s){if(s>0||e.reverse){var d=t.getDistanceFromCenterForValue(t.ticksAsNumbers[s]),h=t.yCenter-d;if(n.display&&0!==s&&c(t,n,d,s),i.display){var f=a(i.fontColor,g.defaultFontColor);if(o.font=u,i.showLabelBackdrop){var p=o.measureText(l).width;o.fillStyle=i.backdropColor,o.fillRect(t.xCenter-p/2-i.backdropPaddingX,h-r/2-i.backdropPaddingY,p+2*i.backdropPaddingX,r+2*i.backdropPaddingY)}o.textAlign="center",o.textBaseline="middle",o.fillStyle=f,o.fillText(l,t.xCenter,h)}}}),(e.angleLines.display||e.pointLabels.display)&&d(t)}}});t.scaleService.registerScaleType("radialLinear",m,p)}},{}],49:[function(t,e,n){"use strict";var i=t(1);i="function"==typeof i?i:window.moment,e.exports=function(t){function e(t,e){var n=t.options.time;if("string"==typeof n.parser)return i(e,n.parser);if("function"==typeof n.parser)return n.parser(e);if("function"==typeof e.getMonth||"number"==typeof e)return i(e);if(e.isValid&&e.isValid())return e;var a=n.format;return"string"!=typeof a&&a.call?(console.warn("options.time.format is deprecated and replaced by options.time.parser."),a(e)):i(e,a)}function n(t,e,n,i){for(var a,o=Object.keys(l),r=o.length,s=o.indexOf(t);si;c++)s=a.steps[c],r=Math.ceil(u/(o*s));else for(;r>i&&i>0;)++s,r=Math.ceil(u/(o*s));return s}function o(t,e,n){var a=[];if(t.maxTicks){var o=t.stepSize;a.push(void 0!==t.min?t.min:n.min);for(var r=i(n.min);r.add(o,t.unit).valueOf()0&&a.add(1,"week"),a=a.valueOf()):(n=i(e.min).startOf(t.unit).valueOf(),a=i(e.max).startOf(t.unit),e.max-a>0&&a.add(1,t.unit),a=a.valueOf()),o(t,e,{min:n,max:a})};var u=t.Scale.extend({initialize:function(){if(!i)throw new Error("Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com");t.Scale.prototype.initialize.call(this)},determineDataLimits:function(){var t,n=this,i=n.options.time,a=Number.MAX_SAFE_INTEGER,o=Number.MIN_SAFE_INTEGER,l=n.chart.data,s={labels:[],datasets:[]};r.each(l.labels,function(r,l){var u=e(n,r);u.isValid()&&(i.round&&u.startOf(i.round),t=u.valueOf(),a=Math.min(t,a),o=Math.max(t,o),s.labels[l]=t)}),r.each(l.datasets,function(l,u){var d=[];"object"==typeof l.data[0]&&null!==l.data[0]&&n.chart.isDatasetVisible(u)?r.each(l.data,function(r,l){var s=e(n,n.getRightValue(r));s.isValid()&&(i.round&&s.startOf(i.round),t=s.valueOf(),a=Math.min(t,a),o=Math.max(t,o),d[l]=t)}):d=s.labels.slice(),s.datasets[u]=d}),n.dataMin=a,n.dataMax=o,n._parsedData=s},buildTicks:function(){var i,o,l=this,s=l.options.time,u=l.dataMin,d=l.dataMax;if(s.min){var c=e(l,s.min);s.round&&c.round(s.round),i=c.valueOf()}s.max&&(o=e(l,s.max).valueOf());var h=l.getLabelCapacity(i||u),f=s.unit||n(s.minUnit,i||u,o||d,h);l.displayFormat=s.displayFormats[f];var g=s.stepSize||a(i||u,o||d,f,h);l.ticks=t.Ticks.generators.time({maxTicks:h,min:i,max:o,stepSize:g,unit:f,isoWeekday:s.isoWeekday},{min:u,max:d}),l.max=r.max(l.ticks),l.min=r.min(l.ticks)},getLabelForIndex:function(t,n){var i=this,a=i.chart.data.labels&&t
-
-```
-
-To import Chart.js using an awesome module loader:
-
-```javascript
-
-// Using CommonJS
-var Chart = require('src/chart.js')
-var myChart = new Chart({...})
-
-// ES6
-import Chart from 'src/chart.js'
-let myChart = new Chart({...})
-
-// Using requirejs
-require(['path/to/Chartjs'], function(Chart){
- var myChart = new Chart({...})
-})
-
-```
-
-### Creating a Chart
-
-To create a chart, we need to instantiate the `Chart` class. To do this, we need to pass in the node, jQuery instance, or 2d context of the canvas of where we want to draw the chart. Here's an example.
-
-```html
-
-```
-
-```javascript
-// Any of the following formats may be used
-var ctx = document.getElementById("myChart");
-var ctx = document.getElementById("myChart").getContext("2d");
-var ctx = $("#myChart");
-var ctx = "myChart";
-```
-
-Once you have the element or context, you're ready to instantiate a pre-defined chart-type or create your own!
-
-The following example instantiates a bar chart showing the number of votes for different colors and the y-axis starting at 0.
-
-```html
-
-
-```
-
-It's that easy to get started using Chart.js! From here you can explore the many options that can help you customise your charts with scales, tooltips, labels, colors, custom actions, and much more.
-
-There are many examples of Chart.js that are available in the `/samples` folder of `Chart.js.zip` that is attatched to every [release](https://github.com/chartjs/Chart.js/releases).
diff --git a/contao/assets/chartjs/docs/01-Chart-Configuration.md b/contao/assets/chartjs/docs/01-Chart-Configuration.md
deleted file mode 100644
index a469220..0000000
--- a/contao/assets/chartjs/docs/01-Chart-Configuration.md
+++ /dev/null
@@ -1,517 +0,0 @@
----
-title: Chart Configuration
-anchor: chart-configuration
----
-
-Chart.js provides a number of options for changing the behaviour of created charts. These configuration options can be changed on a per chart basis by passing in an options object when creating the chart. Alternatively, the global configuration can be changed which will be used by all charts created after that point.
-
-### Chart Data
-
-To display data, the chart must be passed a data object that contains all of the information needed by the chart. The data object can contain the following parameters
-
-Name | Type | Description
---- | --- | ----
-datasets | Array[object] | Contains data for each dataset. See the documentation for each chart type to determine the valid options that can be attached to the dataset
-labels | Array[string] | Optional parameter that is used with the [category axis](#scales-category-scale).
-xLabels | Array[string] | Optional parameter that is used with the category axis and is used if the axis is horizontal
-yLabels | Array[string] | Optional parameter that is used with the category axis and is used if the axis is vertical
-
-### Creating a Chart with Options
-
-To create a chart with configuration options, simply pass an object containing your configuration to the constructor. In the example below, a line chart is created and configured to not be responsive.
-
-```javascript
-var chartInstance = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- responsive: false
- }
-});
-```
-
-### Global Configuration
-
-This concept was introduced in Chart.js 1.0 to keep configuration [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), and allow for changing options globally across chart types, avoiding the need to specify options for each instance, or the default for a particular chart type.
-
-Chart.js merges the options object passed to the chart with the global configuration using chart type defaults and scales defaults appropriately. This way you can be as specific as you would like in your individual chart configuration, while still changing the defaults for all chart types where applicable. The global general options are defined in `Chart.defaults.global`. The defaults for each chart type are discussed in the documentation for that chart type.
-
-The following example would set the hover mode to 'nearest' for all charts where this was not overridden by the chart type defaults or the options passed to the constructor on creation.
-
-```javascript
-Chart.defaults.global.hover.mode = 'nearest';
-
-// Hover mode is set to nearest because it was not overridden here
-var chartInstanceHoverModeNearest = new Chart(ctx, {
- type: 'line',
- data: data,
-});
-
-// This chart would have the hover mode that was passed in
-var chartInstanceDifferentHoverMode = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- hover: {
- // Overrides the global setting
- mode: 'index'
- }
- }
-})
-```
-
-#### Global Font Settings
-
-There are 4 special global settings that can change all of the fonts on the chart. These options are in `Chart.defaults.global`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-defaultFontColor | Color | '#666' | Default font color for all text
-defaultFontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Default font family for all text
-defaultFontSize | Number | 12 | Default font size (in px) for text. Does not apply to radialLinear scale point labels
-defaultFontStyle | String | 'normal' | Default font style. Does not apply to tooltip title or footer. Does not apply to chart title
-
-### Common Chart Configuration
-
-The following options are applicable to all charts. The can be set on the [global configuration](#chart-configuration-global-configuration), or they can be passed to the chart constructor.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-responsive | Boolean | true | Resizes the chart canvas when its container does.
-responsiveAnimationDuration | Number | 0 | Duration in milliseconds it takes to animate to new size after a resize event.
-maintainAspectRatio | Boolean | true | Maintain the original canvas aspect ratio `(width / height)` when resizing
-events | Array[String] | `["mousemove", "mouseout", "click", "touchstart", "touchmove", "touchend"]` | Events that the chart should listen to for tooltips and hovering
-onClick | Function | null | Called if the event is of type 'mouseup' or 'click'. Called in the context of the chart and passed an array of active elements
-legendCallback | Function | ` function (chart) { }` | Function to generate a legend. Receives the chart object to generate a legend from. Default implementation returns an HTML string.
-onResize | Function | null | Called when a resize occurs. Gets passed two arguments: the chart instance and the new size.
-
-### Layout Configuration
-
-The layout configuration is passed into the `options.layout` namespace. The global options for the chart layout is defined in `Chart.defaults.global.layout`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-padding | Number or Object | 0 | The padding to add inside the chart. If this value is a number, it is applied to all sides of the chart (left, top, right, bottom). If this value is an object, the `left` property defines the left padding. Similarly the `right`, `top`, and `bottom` properties can also be specified.
-
-
-### Title Configuration
-
-The title configuration is passed into the `options.title` namespace. The global options for the chart title is defined in `Chart.defaults.global.title`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-display | Boolean | false | Display the title block
-position | String | 'top' | Position of the title. Possible values are 'top', 'left', 'bottom' and 'right'.
-fullWidth | Boolean | true | Marks that this box should take the full width of the canvas (pushing down other boxes)
-fontSize | Number | 12 | Font size inherited from global configuration
-fontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family inherited from global configuration
-fontColor | Color | "#666" | Font color inherited from global configuration
-fontStyle | String | 'bold' | Font styling of the title.
-padding | Number | 10 | Number of pixels to add above and below the title text
-text | String | '' | Title text
-
-#### Example Usage
-
-The example below would enable a title of 'Custom Chart Title' on the chart that is created.
-
-```javascript
-var chartInstance = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- title: {
- display: true,
- text: 'Custom Chart Title'
- }
- }
-})
-```
-
-### Legend Configuration
-
-The legend configuration is passed into the `options.legend` namespace. The global options for the chart legend is defined in `Chart.defaults.global.legend`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-display | Boolean | true | Is the legend displayed
-position | String | 'top' | Position of the legend. Possible values are 'top', 'left', 'bottom' and 'right'.
-fullWidth | Boolean | true | Marks that this box should take the full width of the canvas (pushing down other boxes)
-onClick | Function | `function(event, legendItem) {}` | A callback that is called when a 'click' event is registered on top of a label item
-onHover | Function | `function(event, legendItem) {}` | A callback that is called when a 'mousemove' event is registered on top of a label item
-labels |Object|-| See the [Legend Label Configuration](#chart-configuration-legend-label-configuration) section below.
-reverse | Boolean | false | Legend will show datasets in reverse order
-
-#### Legend Label Configuration
-
-The legend label configuration is nested below the legend configuration using the `labels` key.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-boxWidth | Number | 40 | Width of coloured box
-fontSize | Number | 12 | Font size inherited from global configuration
-fontStyle | String | "normal" | Font style inherited from global configuration
-fontColor | Color | "#666" | Font color inherited from global configuration
-fontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family inherited from global configuration
-padding | Number | 10 | Padding between rows of colored boxes
-generateLabels: | Function | `function(chart) { }` | Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. See [Legend Item](#chart-configuration-legend-item-interface) for details.
-usePointStyle | Boolean | false | Label style will match corresponding point style (size is based on fontSize, boxWidth is not used in this case).
-
-#### Legend Item Interface
-
-Items passed to the legend `onClick` function are the ones returned from `labels.generateLabels`. These items must implement the following interface.
-
-```javascript
-{
- // Label that will be displayed
- text: String,
-
- // Fill style of the legend box
- fillStyle: Color,
-
- // If true, this item represents a hidden dataset. Label will be rendered with a strike-through effect
- hidden: Boolean,
-
- // For box border. See https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap
- lineCap: String,
-
- // For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
- lineDash: Array[Number],
-
- // For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
- lineDashOffset: Number,
-
- // For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin
- lineJoin: String,
-
- // Width of box border
- lineWidth: Number,
-
- // Stroke style of the legend box
- strokeStyle: Color
-
- // Point style of the legend box (only used if usePointStyle is true)
- pointStyle: String
-}
-```
-
-#### Example
-
-The following example will create a chart with the legend enabled and turn all of the text red in color.
-
-```javascript
-var chartInstance = new Chart(ctx, {
- type: 'bar',
- data: data,
- options: {
- legend: {
- display: true,
- labels: {
- fontColor: 'rgb(255, 99, 132)'
- }
- }
-}
-});
-```
-
-### Tooltip Configuration
-
-The tooltip configuration is passed into the `options.tooltips` namespace. The global options for the chart tooltips is defined in `Chart.defaults.global.tooltips`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-enabled | Boolean | true | Are tooltips enabled
-custom | Function | null | See [section](#advanced-usage-external-tooltips) below
-mode | String | 'nearest' | Sets which elements appear in the tooltip. See [Interaction Modes](#interaction-modes) for details
-intersect | Boolean | true | if true, the tooltip mode applies only when the mouse position intersects with an element. If false, the mode will be applied at all times.
-position | String | 'average' | The mode for positioning the tooltip. 'average' mode will place the tooltip at the average position of the items displayed in the tooltip. 'nearest' will place the tooltip at the position of the element closest to the event position. New modes can be defined by adding functions to the Chart.Tooltip.positioners map.
-itemSort | Function | undefined | Allows sorting of [tooltip items](#chart-configuration-tooltip-item-interface). Must implement at minimum a function that can be passed to [Array.prototype.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort). This function can also accept a third parameter that is the data object passed to the chart.
-filter | Function | undefined | Allows filtering of [tooltip items](#chart-configuration-tooltip-item-interface). Must implement at minimum a function that can be passed to [Array.prototype.filter](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter). This function can also accept a second parameter that is the data object passed to the chart.
-backgroundColor | Color | 'rgba(0,0,0,0.8)' | Background color of the tooltip
-titleFontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family for tooltip title inherited from global font family
-titleFontSize | Number | 12 | Font size for tooltip title inherited from global font size
-titleFontStyle | String | "bold" |
-titleFontColor | Color | "#fff" | Font color for tooltip title
-titleSpacing | Number | 2 | Spacing to add to top and bottom of each title line.
-titleMarginBottom | Number | 6 | Margin to add on bottom of title section
-bodyFontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family for tooltip items inherited from global font family
-bodyFontSize | Number | 12 | Font size for tooltip items inherited from global font size
-bodyFontStyle | String | "normal" |
-bodyFontColor | Color | "#fff" | Font color for tooltip items.
-bodySpacing | Number | 2 | Spacing to add to top and bottom of each tooltip item
-footerFontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family for tooltip footer inherited from global font family.
-footerFontSize | Number | 12 | Font size for tooltip footer inherited from global font size.
-footerFontStyle | String | "bold" | Font style for tooltip footer.
-footerFontColor | Color | "#fff" | Font color for tooltip footer.
-footerSpacing | Number | 2 | Spacing to add to top and bottom of each footer line.
-footerMarginTop | Number | 6 | Margin to add before drawing the footer
-xPadding | Number | 6 | Padding to add on left and right of tooltip
-yPadding | Number | 6 | Padding to add on top and bottom of tooltip
-caretSize | Number | 5 | Size, in px, of the tooltip arrow
-cornerRadius | Number | 6 | Radius of tooltip corner curves
-multiKeyBackground | Color | "#fff" | Color to draw behind the colored boxes when multiple items are in the tooltip
-displayColors | Boolean | true | if true, color boxes are shown in the tooltip
-callbacks | Object | | See the [callbacks section](#chart-configuration-tooltip-callbacks) below
-
-#### Tooltip Callbacks
-
-The tooltip label configuration is nested below the tooltip configuration using the `callbacks` key. The tooltip has the following callbacks for providing text. For all functions, 'this' will be the tooltip object created from the Chart.Tooltip constructor.
-
-All functions are called with the same arguments: a [tooltip item](#chart-configuration-tooltip-item-interface) and the data object passed to the chart. All functions must return either a string or an array of strings. Arrays of strings are treated as multiple lines of text.
-
-Callback | Arguments | Description
---- | --- | ---
-beforeTitle | `Array[tooltipItem], data` | Text to render before the title
-title | `Array[tooltipItem], data` | Text to render as the title
-afterTitle | `Array[tooltipItem], data` | Text to render after the title
-beforeBody | `Array[tooltipItem], data` | Text to render before the body section
-beforeLabel | `tooltipItem, data` | Text to render before an individual label
-label | `tooltipItem, data` | Text to render for an individual item in the tooltip
-labelColor | `tooltipItem, chartInstance` | Returns the colors to render for the tooltip item. Return as an object containing two parameters: `borderColor` and `backgroundColor`.
-afterLabel | `tooltipItem, data` | Text to render after an individual label
-afterBody | `Array[tooltipItem], data` | Text to render after the body section
-beforeFooter | `Array[tooltipItem], data` | Text to render before the footer section
-footer | `Array[tooltipItem], data` | Text to render as the footer
-afterFooter | `Array[tooltipItem], data` | Text to render after the footer section
-dataPoints | `Array[tooltipItem]` | List of matching point informations.
-
-#### Tooltip Item Interface
-
-The tooltip items passed to the tooltip callbacks implement the following interface.
-
-```javascript
-{
- // X Value of the tooltip as a string
- xLabel: String,
-
- // Y value of the tooltip as a string
- yLabel: String,
-
- // Index of the dataset the item comes from
- datasetIndex: Number,
-
- // Index of this data item in the dataset
- index: Number,
-
- // X position of matching point
- x: Number,
-
- // Y position of matching point
- y: Number,
-}
-```
-
-### Hover Configuration
-
-The hover configuration is passed into the `options.hover` namespace. The global hover configuration is at `Chart.defaults.global.hover`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-mode | String | 'nearest' | Sets which elements appear in the tooltip. See [Interaction Modes](#interaction-modes) for details
-intersect | Boolean | true | if true, the hover mode only applies when the mouse position intersects an item on the chart
-animationDuration | Number | 400 | Duration in milliseconds it takes to animate hover style changes
-onHover | Function | null | Called when any of the events fire. Called in the context of the chart and passed an array of active elements (bars, points, etc)
-
-### Interaction Modes
-When configuring interaction with the graph via hover or tooltips, a number of different modes are available.
-
-The following table details the modes and how they behave in conjunction with the `intersect` setting
-
-Mode | Behaviour
---- | ---
-point | Finds all of the items that intersect the point
-nearest | Gets the item that is nearest to the point. The nearest item is determined based on the distance to the center of the chart item (point, bar). If 2 or more items are at the same distance, the one with the smallest area is used. If `intersect` is true, this is only triggered when the mouse position intersects an item in the graph. This is very useful for combo charts where points are hidden behind bars.
-single (deprecated) | Finds the first item that intersects the point and returns it. Behaves like 'nearest' mode with intersect = true.
-label (deprecated) | See `'index'` mode
-index | Finds item at the same index. If the `intersect` setting is true, the first intersecting item is used to determine the index in the data. If `intersect` false the nearest item is used to determine the index.
-x-axis (deprecated) | Behaves like `'index'` mode with `intersect = true`
-dataset | Finds items in the same dataset. If the `intersect` setting is true, the first intersecting item is used to determine the index in the data. If `intersect` false the nearest item is used to determine the index.
-x | Returns all items that would intersect based on the `X` coordinate of the position only. Would be useful for a vertical cursor implementation. Note that this only applies to cartesian charts
-y | Returns all items that would intersect based on the `Y` coordinate of the position. This would be useful for a horizontal cursor implementation. Note that this only applies to cartesian charts.
-
-### Animation Configuration
-
-The following animation options are available. The global options for are defined in `Chart.defaults.global.animation`.
-
-Name | Type | Default | Description
---- |:---:| --- | ---
-duration | Number | 1000 | The number of milliseconds an animation takes.
-easing | String | "easeOutQuart" | Easing function to use. Available options are: `'linear'`, `'easeInQuad'`, `'easeOutQuad'`, `'easeInOutQuad'`, `'easeInCubic'`, `'easeOutCubic'`, `'easeInOutCubic'`, `'easeInQuart'`, `'easeOutQuart'`, `'easeInOutQuart'`, `'easeInQuint'`, `'easeOutQuint'`, `'easeInOutQuint'`, `'easeInSine'`, `'easeOutSine'`, `'easeInOutSine'`, `'easeInExpo'`, `'easeOutExpo'`, `'easeInOutExpo'`, `'easeInCirc'`, `'easeOutCirc'`, `'easeInOutCirc'`, `'easeInElastic'`, `'easeOutElastic'`, `'easeInOutElastic'`, `'easeInBack'`, `'easeOutBack'`, `'easeInOutBack'`, `'easeInBounce'`, `'easeOutBounce'`, `'easeInOutBounce'`. See [Robert Penner's easing equations](http://robertpenner.com/easing/).
-onProgress | Function | none | Callback called on each step of an animation. Passed a single argument, an object, containing the chart instance and an object with details of the animation.
-onComplete | Function | none | Callback called at the end of an animation. Passed the same arguments as `onProgress`
-
-#### Animation Callbacks
-
-The `onProgress` and `onComplete` callbacks are useful for synchronizing an external draw to the chart animation. The callback is passed an object that implements the following interface. An example usage of these callbacks can be found on [Github](https://github.com/chartjs/Chart.js/blob/master/samples/AnimationCallbacks/progress-bar.html). This sample displays a progress bar showing how far along the animation is.
-
-```javascript
-{
- // Chart object
- chartInstance,
-
- // Contains details of the on-going animation
- animationObject,
-}
-```
-
-#### Animation Object
-
-The animation object passed to the callbacks is of type `Chart.Animation`. The object has the following parameters.
-
-```javascript
-{
- // Current Animation frame number
- currentStep: Number,
-
- // Number of animation frames
- numSteps: Number,
-
- // Animation easing to use
- easing: String,
-
- // Function that renders the chart
- render: Function,
-
- // User callback
- onAnimationProgress: Function,
-
- // User callback
- onAnimationComplete: Function
-}
-```
-
-### Element Configuration
-
-The global options for elements are defined in `Chart.defaults.global.elements`.
-
-Options can be configured for four different types of elements: arc, lines, points, and rectangles. When set, these options apply to all objects of that type unless specifically overridden by the configuration attached to a dataset.
-
-#### Arc Configuration
-
-Arcs are used in the polar area, doughnut and pie charts. They can be configured with the following options. The global arc options are stored in `Chart.defaults.global.elements.arc`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-backgroundColor | Color | 'rgba(0,0,0,0.1)' | Default fill color for arcs. Inherited from the global default
-borderColor | Color | '#fff' | Default stroke color for arcs
-borderWidth | Number | 2 | Default stroke width for arcs
-
-#### Line Configuration
-
-Line elements are used to represent the line in a line chart. The global line options are stored in `Chart.defaults.global.elements.line`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-tension | Number | 0.4 | Default bezier curve tension. Set to `0` for no bezier curves.
-backgroundColor | Color | 'rgba(0,0,0,0.1)' | Default line fill color
-borderWidth | Number | 3 | Default line stroke width
-borderColor | Color | 'rgba(0,0,0,0.1)' | Default line stroke color
-borderCapStyle | String | 'butt' | Default line cap style. See [MDN](https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap)
-borderDash | Array | `[]` | Default line dash. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
-borderDashOffset | Number | 0.0 | Default line dash offset. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
-borderJoinStyle | String | 'miter' | Default line join style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
-capBezierPoints | Boolean | true | If true, bezier control points are kept inside the chart. If false, no restriction is enforced.
-fill | Boolean or String | true | If true, the fill is assumed to be to zero. String values are 'zero', 'top', and 'bottom' to fill to different locations. If `false`, no fill is added
-stepped | Boolean | false | If true, the line is shown as a stepped line and 'tension' will be ignored
-
-#### Point Configuration
-
-Point elements are used to represent the points in a line chart or a bubble chart. The global point options are stored in `Chart.defaults.global.elements.point`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-radius | Number | 3 | Default point radius
-pointStyle | String | 'circle' | Default point style
-backgroundColor | Color | 'rgba(0,0,0,0.1)' | Default point fill color
-borderWidth | Number | 1 | Default point stroke width
-borderColor | Color | 'rgba(0,0,0,0.1)' | Default point stroke color
-hitRadius | Number | 1 | Extra radius added to point radius for hit detection
-hoverRadius | Number | 4 | Default point radius when hovered
-hoverBorderWidth | Number | 1 | Default stroke width when hovered
-
-#### Rectangle Configuration
-
-Rectangle elements are used to represent the bars in a bar chart. The global rectangle options are stored in `Chart.defaults.global.elements.rectangle`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-backgroundColor | Color | 'rgba(0,0,0,0.1)' | Default bar fill color
-borderWidth | Number | 0 | Default bar stroke width
-borderColor | Color | 'rgba(0,0,0,0.1)' | Default bar stroke color
-borderSkipped | String | 'bottom' | Default skipped (excluded) border for rectangle. Can be one of `bottom`, `left`, `top`, `right`
-
-### Colors
-
-When supplying colors to Chart options, you can use a number of formats. You can specify the color as a string in hexadecimal, RGB, or HSL notations. If a color is needed, but not specified, Chart.js will use the global default color. This color is stored at `Chart.defaults.global.defaultColor`. It is initially set to 'rgba(0, 0, 0, 0.1)';
-
-You can also pass a [CanvasGradient](https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient) object. You will need to create this before passing to the chart, but using it you can achieve some interesting effects.
-
-### Patterns
-
-An alternative option is to pass a [CanvasPattern](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern) object. For example, if you wanted to fill a dataset with a pattern from an image you could do the following.
-
-```javascript
-var img = new Image();
-img.src = 'https://example.com/my_image.png';
-img.onload = function() {
- var ctx = document.getElementById('canvas').getContext('2d');
- var fillPattern = ctx.createPattern(img, 'repeat');
-
- var chart = new Chart(ctx, {
- data: {
- labels: ['Item 1', 'Item 2', 'Item 3'],
- datasets: [{
- data: [10, 20, 30],
- backgroundColor: fillPattern
- }]
- }
- })
-}
-```
-
-Using pattern fills for data graphics can help viewers with vision deficiencies (e.g. color-blindness or partial sight) to [more easily understand your data](http://betweentwobrackets.com/data-graphics-and-colour-vision/).
-
-Using the [Patternomaly](https://github.com/ashiguruma/patternomaly) library you can generate patterns to fill datasets.
-
-```javascript
-var chartData = {
- datasets: [{
- data: [45, 25, 20, 10],
- backgroundColor: [
- pattern.draw('square', '#ff6384'),
- pattern.draw('circle', '#36a2eb'),
- pattern.draw('diamond', '#cc65fe'),
- pattern.draw('triangle', '#ffce56'),
- ]
- }],
- labels: ['Red', 'Blue', 'Purple', 'Yellow']
-};
-```
-
-### Mixed Chart Types
-
-When creating a chart, you have the option to overlay different chart types on top of each other as separate datasets.
-
-To do this, you must set a `type` for each dataset individually. You can create mixed chart types with bar and line chart types.
-
-When creating the chart you must set the overall `type` as `bar`.
-
-```javascript
-var myChart = new Chart(ctx, {
- type: 'bar',
- data: {
- labels: ['Item 1', 'Item 2', 'Item 3'],
- datasets: [
- {
- type: 'bar',
- label: 'Bar Component',
- data: [10, 20, 30],
- },
- {
- type: 'line',
- label: 'Line Component',
- data: [30, 20, 10],
- }
- ]
- }
-});
-```
diff --git a/contao/assets/chartjs/docs/02-Scales.md b/contao/assets/chartjs/docs/02-Scales.md
deleted file mode 100644
index ae77583..0000000
--- a/contao/assets/chartjs/docs/02-Scales.md
+++ /dev/null
@@ -1,369 +0,0 @@
----
-title: Scales
-anchor: scales
----
-
-Scales in v2.0 of Chart.js are significantly more powerful, but also different than those of v1.0.
-* Multiple X & Y axes are supported.
-* A built-in label auto-skip feature detects would-be overlapping ticks and labels and removes every nth label to keep things displaying normally.
-* Scale titles are supported
-* New scale types can be extended without writing an entirely new chart type
-
-
-### Common Configuration
-
-Every scale extends a core scale class with the following options:
-
-Name | Type | Default | Description
---- | --- | --- | ---
-type | String | Chart specific. | Type of scale being employed. Custom scales can be created and registered with a string key. Options: ["category"](#scales-category-scale), ["linear"](#scales-linear-scale), ["logarithmic"](#scales-logarithmic-scale), ["time"](#scales-time-scale), ["radialLinear"](#scales-radial-linear-scale)
-display | Boolean | true | If true, show the scale including gridlines, ticks, and labels. Overrides *gridLines.display*, *scaleLabel.display*, and *ticks.display*.
-position | String | "left" | Position of the scale. Possible values are 'top', 'left', 'bottom' and 'right'.
-id | String | | The ID is used to link datasets and scale axes together. The properties `datasets.xAxisID` or `datasets.yAxisID` have to match the scale properties `scales.xAxes.id` or `scales.yAxes.id`. This is especially needed if multi-axes charts are used.
-beforeUpdate | Function | undefined | Callback called before the update process starts. Passed a single argument, the scale instance.
-beforeSetDimensions | Function | undefined | Callback that runs before dimensions are set. Passed a single argument, the scale instance.
-afterSetDimensions | Function | undefined | Callback that runs after dimensions are set. Passed a single argument, the scale instance.
-beforeDataLimits | Function | undefined | Callback that runs before data limits are determined. Passed a single argument, the scale instance.
-afterDataLimits | Function | undefined | Callback that runs after data limits are determined. Passed a single argument, the scale instance.
-beforeBuildTicks | Function | undefined | Callback that runs before ticks are created. Passed a single argument, the scale instance.
-afterBuildTicks | Function | undefined | Callback that runs after ticks are created. Useful for filtering ticks. Passed a single argument, the scale instance.
-beforeTickToLabelConversion | Function | undefined | Callback that runs before ticks are converted into strings. Passed a single argument, the scale instance.
-afterTickToLabelConversion | Function | undefined | Callback that runs after ticks are converted into strings. Passed a single argument, the scale instance.
-beforeCalculateTickRotation | Function | undefined | Callback that runs before tick rotation is determined. Passed a single argument, the scale instance.
-afterCalculateTickRotation | Function | undefined | Callback that runs after tick rotation is determined. Passed a single argument, the scale instance.
-beforeFit | Function | undefined | Callback that runs before the scale fits to the canvas. Passed a single argument, the scale instance.
-afterFit | Function | undefined | Callback that runs after the scale fits to the canvas. Passed a single argument, the scale instance.
-afterUpdate | Function | undefined | Callback that runs at the end of the update process. Passed a single argument, the scale instance.
-**gridLines** | Object | - | See [grid line configuration](#grid-line-configuration) section.
-**scaleLabel** | Object | | See [scale title configuration](#scale-title-configuration) section.
-**ticks** | Object | | See [ticks configuration](#ticks-configuration) section.
-
-#### Grid Line Configuration
-
-The grid line configuration is nested under the scale configuration in the `gridLines` key. It defines options for the grid lines that run perpendicular to the axis.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-display | Boolean | true |
-color | Color or Array[Color] | "rgba(0, 0, 0, 0.1)" | Color of the grid lines.
-borderDash | Array[Number] | [] | Length and spacing of dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
-borderDashOffset | Number | 0.0 | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
-lineWidth | Number or Array[Number] | 1 | Stroke width of grid lines
-drawBorder | Boolean | true | If true draw border on the edge of the chart
-drawOnChartArea | Boolean | true | If true, draw lines on the chart area inside the axis lines. This is useful when there are multiple axes and you need to control which grid lines are drawn
-drawTicks | Boolean | true | If true, draw lines beside the ticks in the axis area beside the chart.
-tickMarkLength | Number | 10 | Length in pixels that the grid lines will draw into the axis area.
-zeroLineWidth | Number | 1 | Stroke width of the grid line for the first index (index 0).
-zeroLineColor | Color | "rgba(0, 0, 0, 0.25)" | Stroke color of the grid line for the first index (index 0).
-offsetGridLines | Boolean | false | If true, labels are shifted to be between grid lines. This is used in the bar chart.
-
-#### Scale Title Configuration
-
-The scale label configuration is nested under the scale configuration in the `scaleLabel` key. It defines options for the scale title.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-display | Boolean | false |
-labelString | String | "" | The text for the title. (i.e. "# of People", "Response Choices")
-fontColor | Color | "#666" | Font color for the scale title.
-fontFamily| String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family for the scale title, follows CSS font-family options.
-fontSize | Number | 12 | Font size for the scale title.
-fontStyle | String | "normal" | Font style for the scale title, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
-
-#### Tick Configuration
-
-The tick configuration is nested under the scale configuration in the `ticks` key. It defines options for the tick marks that are generated by the axis.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-autoSkip | Boolean | true | If true, automatically calculates how many labels that can be shown and hides labels accordingly. Turn it off to show all labels no matter what
-autoSkipPadding | Number | 0 | Padding between the ticks on the horizontal axis when `autoSkip` is enabled. *Note: Only applicable to horizontal scales.*
-callback | Function | `function(value) { return helpers.isArray(value) ? value : '' + value; }` | Returns the string representation of the tick value as it should be displayed on the chart. See [callback](#scales-creating-custom-tick-formats) section below.
-display | Boolean | true | If true, show the ticks.
-fontColor | Color | "#666" | Font color for the tick labels.
-fontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family for the tick labels, follows CSS font-family options.
-fontSize | Number | 12 | Font size for the tick labels.
-fontStyle | String | "normal" | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
-labelOffset | Number | 0 | Distance in pixels to offset the label from the centre point of the tick (in the y direction for the x axis, and the x direction for the y axis). *Note: this can cause labels at the edges to be cropped by the edge of the canvas*
-maxRotation | Number | 90 | Maximum rotation for tick labels when rotating to condense labels. Note: Rotation doesn't occur until necessary. *Note: Only applicable to horizontal scales.*
-minRotation | Number | 0 | Minimum rotation for tick labels. *Note: Only applicable to horizontal scales.*
-mirror | Boolean | false | Flips tick labels around axis, displaying the labels inside the chart instead of outside. *Note: Only applicable to vertical scales.*
-padding | Number | 10 | Padding between the tick label and the axis. *Note: Only applicable to horizontal scales.*
-reverse | Boolean | false | Reverses order of tick labels.
-
-#### Creating Custom Tick Formats
-
-The `callback` method may be used for advanced tick customization. In the following example, every label of the Y axis would be displayed in scientific notation.
-
-If the callback returns `null` or `undefined` the associated grid line will be hidden.
-
-```javascript
-var chartInstance = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- scales: {
- yAxes: [{
- ticks: {
- // Create scientific notation labels
- callback: function(value, index, values) {
- return value.toExponential();
- }
- }
- }]
- }
- }
-});
-```
-
-### Category Scale
-
-The category scale will be familiar to those who have used v1.0. Labels are drawn from one of the label arrays included in the chart data. If only `data.labels` is defined, this will be used. If `data.xLabels` is defined and the axis is horizontal, this will be used. Similarly, if `data.yLabels` is defined and the axis is vertical, this property will be used. Using both `xLabels` and `yLabels` together can create a chart that uses strings for both the X and Y axes.
-
-#### Configuration Options
-
-The category scale has the following additional options that can be set.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-ticks.min | String | - | The minimum item to display. Must be a value in the `labels` array
-ticks.max | String | - | The maximum item to display. Must be a value in the `labels` array
-
-### Linear Scale
-
-The linear scale is use to chart numerical data. It can be placed on either the x or y axis. The scatter chart type automatically configures a line chart to use one of these scales for the x axis. As the name suggests, linear interpolation is used to determine where a value lies on the axis.
-
-#### Configuration Options
-
-The following options are provided by the linear scale. They are all located in the `ticks` sub options.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-beginAtZero | Boolean | - | if true, scale will include 0 if it is not already included.
-min | Number | - | User defined minimum number for the scale, overrides minimum value from data.
-max | Number | - | User defined maximum number for the scale, overrides maximum value from data.
-maxTicksLimit | Number | 11 | Maximum number of ticks and gridlines to show. If not defined, it will limit to 11 ticks but will show all gridlines.
-fixedStepSize | Number | - | User defined fixed step size for the scale. If set, the scale ticks will be enumerated by multiple of stepSize, having one tick per increment. If not set, the ticks are labeled automatically using the nice numbers algorithm.
-stepSize | Number | - | if defined, it can be used along with the min and the max to give a custom number of steps. See the example below.
-suggestedMax | Number | - | User defined maximum number for the scale, overrides maximum value *except for if* it is lower than the maximum value.
-suggestedMin | Number | - | User defined minimum number for the scale, overrides minimum value *except for if* it is higher than the minimum value.
-
-#### Example Configuration
-
-The following example creates a line chart with a vertical axis that goes from 0 to 5 in 0.5 sized steps.
-
-```javascript
-var chartInstance = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- scales: {
- yAxes: [{
- ticks: {
- max: 5,
- min: 0,
- stepSize: 0.5
- }
- }]
- }
- }
-});
-```
-
-### Logarithmic Scale
-
-The logarithmic scale is use to chart numerical data. It can be placed on either the x or y axis. As the name suggests, logarithmic interpolation is used to determine where a value lies on the axis.
-
-#### Configuration Options
-
-The following options are provided by the logarithmic scale. They are all located in the `ticks` sub options.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-min | Number | - | User defined minimum number for the scale, overrides minimum value from data.
-max | Number | - | User defined maximum number for the scale, overrides maximum value from data.
-
-#### Example Configuration
-
-The following example creates a chart with a logarithmic X axis that ranges from 1 to 1000.
-
-```javascript
-var chartInstance = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- scales: {
- xAxes: [{
- type: 'logarithmic',
- position: 'bottom',
- ticks: {
- min: 1,
- max: 1000
- }
- }]
- }
- }
-})
-```
-
-### Time Scale
-
-The time scale is used to display times and dates. It can only be placed on the X axis. When building its ticks, it will automatically calculate the most comfortable unit base on the size of the scale.
-
-#### Configuration Options
-
-The following options are provided by the time scale. They are all located in the `time` sub options.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-displayFormats | Object | - | See [Display Formats](#scales-display-formats) section below.
-isoWeekday | Boolean | false | If true and the unit is set to 'week', iso weekdays will be used.
-max | [Time](#scales-date-formats) | - | If defined, this will override the data maximum
-min | [Time](#scales-date-formats) | - | If defined, this will override the data minimum
-parser | String or Function | - | If defined as a string, it is interpreted as a custom format to be used by moment to parse the date. If this is a function, it must return a moment.js object given the appropriate data value.
-round | String | - | If defined, dates will be rounded to the start of this unit. See [Time Units](#scales-time-units) below for the allowed units.
-tooltipFormat | String | '' | The moment js format string to use for the tooltip.
-unit | String | - | If defined, will force the unit to be a certain type. See [Time Units](#scales-time-units) section below for details.
-unitStepSize | Number | 1 | The number of units between grid lines.
-minUnit | String | 'millisecond' | The minimum display format to be used for a time unit
-
-#### Date Formats
-
-When providing data for the time scale, Chart.js supports all of the formats that Moment.js accepts. See [Moment.js docs](http://momentjs.com/docs/#/parsing/) for details.
-
-#### Display Formats
-
-The following display formats are used to configure how different time units are formed into strings for the axis tick marks. See [moment.js](http://momentjs.com/docs/#/displaying/format/) for the allowable format strings.
-
-Name | Default
---- | ---
-millisecond | 'SSS [ms]'
-second | 'h:mm:ss a'
-minute | 'h:mm:ss a'
-hour | 'MMM D, hA'
-day | 'll'
-week | 'll'
-month | 'MMM YYYY'
-quarter | '[Q]Q - YYYY'
-year | 'YYYY'
-
-For example, to set the display format for the 'quarter' unit to show the month and year, the following config would be passed to the chart constructor.
-
-```javascript
-var chartInstance = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- scales: {
- xAxes: [{
- type: 'time',
- time: {
- displayFormats: {
- quarter: 'MMM YYYY'
- }
- }
- }]
- }
- }
-})
-```
-
-#### Time Units
-
-The following time measurements are supported. The names can be passed as strings to the `time.unit` config option to force a certain unit.
-
-* millisecond
-* second
-* minute
-* hour
-* day
-* week
-* month
-* quarter
-* year
-
-For example, to create a chart with a time scale that always displayed units per month, the following config could be used.
-
-```javascript
-var chartInstance = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- scales: {
- xAxes: [{
- time: {
- unit: 'month'
- }
- }]
- }
- }
-})
-```
-
-### Radial Linear Scale
-
-The radial linear scale is used specifically for the radar and polar area chart types. It overlays the chart area, rather than being positioned on one of the edges.
-
-#### Configuration Options
-
-The following additional configuration options are provided by the radial linear scale.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-lineArc | Boolean | false | If true, circular arcs are used else straight lines are used. The former is used by the polar area chart and the latter by the radar chart
-angleLines | Object | - | See the Angle Line Options section below for details.
-pointLabels | Object | - | See the Point Label Options section below for details.
-ticks | Object | - | See the Ticks table below for options.
-
-#### Angle Line Options
-
-The following options are used to configure angled lines that radiate from the center of the chart to the point labels. They can be found in the `angleLines` sub options. Note that these options only apply if `lineArc` is false.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-display | Boolean | true | If true, angle lines are shown.
-color | Color | 'rgba(0, 0, 0, 0.1)' | Color of angled lines
-lineWidth | Number | 1 | Width of angled lines
-
-#### Point Label Options
-
-The following options are used to configure the point labels that are shown on the perimeter of the scale. They can be found in the `pointLabels` sub options. Note that these options only apply if `lineArc` is false.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-callback | Function | - | Callback function to transform data label to axis label
-fontColor | Color | '#666' | Font color
-fontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family to render
-fontSize | Number | 10 | Font size in pixels
-fontStyle | String | 'normal' | Font Style to use
-
-
-#### Tick Options
-
-Name | Type | Default | Description
---- | --- | --- | ---
-backdropColor | Color | 'rgba(255, 255, 255, 0.75)' | Color of label backdrops
-backdropPaddingX | Number | 2 | Horizontal padding of label backdrop
-backdropPaddingY | Number | 2 | Vertical padding of label backdrop
-beginAtZero | Boolean | - | if true, scale will include 0 if it is not already included.
-min | Number | - | User defined minimum number for the scale, overrides minimum value from data.
-max | Number | - | User defined maximum number for the scale, overrides maximum value from data.
-maxTicksLimit | Number | 11 | Maximum number of ticks and gridlines to show. If not defined, it will limit to 11 ticks but will show all gridlines.
-showLabelBackdrop | Boolean | true | If true, draw a background behind the tick labels
-fixedStepSize | Number | - | User defined fixed step size for the scale. If set, the scale ticks will be enumerated by multiple of stepSize, having one tick per increment. If not set, the ticks are labeled automatically using the nice numbers algorithm.
-stepSize | Number | - | if defined, it can be used along with the min and the max to give a custom number of steps. See the example below.
-suggestedMax | Number | - | User defined maximum number for the scale, overrides maximum value *except for if* it is lower than the maximum value.
-suggestedMin | Number | - | User defined minimum number for the scale, overrides minimum value *except for if* it is higher than the minimum value.
-
-### Update Default Scale config
-
-The default configuration for a scale can be easily changed using the scale service. Pass in a partial configuration that will be merged with the current scale default configuration.
-
-For example, to set the minimum value of 0 for all linear scales, you would do the following. Any linear scales created after this time would now have a minimum of 0.
-```
-Chart.scaleService.updateScaleDefaults('linear', {
- ticks: {
- min: 0
- }
-})
-```
diff --git a/contao/assets/chartjs/docs/03-Line-Chart.md b/contao/assets/chartjs/docs/03-Line-Chart.md
deleted file mode 100644
index f62a208..0000000
--- a/contao/assets/chartjs/docs/03-Line-Chart.md
+++ /dev/null
@@ -1,187 +0,0 @@
----
-title: Line Chart
-anchor: line-chart
----
-### Introduction
-A line chart is a way of plotting data points on a line. Often, it is used to show trend data, and the comparison of two data sets.
-
-
-
-
-
-### Example Usage
-```javascript
-var myLineChart = new Chart(ctx, {
- type: 'line',
- data: data,
- options: options
-});
-```
-
-Alternatively a line chart can be created using syntax similar to the v1.0 syntax
-```javascript
-var myLineChart = Chart.Line(ctx, {
- data: data,
- options: options
-});
-```
-
-### Dataset Structure
-
-The following options can be included in a line chart dataset to configure options for that specific dataset.
-
-All point* properties can be specified as an array. If these are set to an array value, the first value applies to the first point, the second value to the second point, and so on.
-
-Property | Type | Usage
---- | --- | ---
-data | See [data point](#line-chart-data-points) section | The data to plot in a line
-label | `String` | The label for the dataset which appears in the legend and tooltips
-xAxisID | `String` | The ID of the x axis to plot this dataset on
-yAxisID | `String` | The ID of the y axis to plot this dataset on
-fill | `Boolean` | If true, fill the area under the line
-cubicInterpolationMode | `String` | Algorithm used to interpolate a smooth curve from the discrete data points. Options are 'default' and 'monotone'. The 'default' algorithm uses a custom weighted cubic interpolation, which produces pleasant curves for all types of datasets. The 'monotone' algorithm is more suited to `y = f(x)` datasets : it preserves monotonicity (or piecewise monotonicity) of the dataset being interpolated, and ensures local extremums (if any) stay at input data points. If left untouched (`undefined`), the global `options.elements.line.cubicInterpolationMode` property is used.
-lineTension | `Number` | Bezier curve tension of the line. Set to 0 to draw straightlines. This option is ignored if monotone cubic interpolation is used. *Note* This was renamed from 'tension' but the old name still works.
-backgroundColor | `Color` | The fill color under the line. See [Colors](#chart-configuration-colors)
-borderWidth | `Number` | The width of the line in pixels
-borderColor | `Color` | The color of the line.
-borderCapStyle | `String` | Cap style of the line. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap)
-borderDash | `Array` | Length and spacing of dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
-borderDashOffset | `Number` | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
-borderJoinStyle | `String` | Line joint style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
-pointBorderColor | `Color or Array` | The border color for points.
-pointBackgroundColor | `Color or Array` | The fill color for points
-pointBorderWidth | `Number or Array` | The width of the point border in pixels
-pointRadius | `Number or Array` | The radius of the point shape. If set to 0, nothing is rendered.
-pointHoverRadius | `Number or Array` | The radius of the point when hovered
-pointHitRadius | `Number or Array` | The pixel size of the non-displayed point that reacts to mouse events
-pointHoverBackgroundColor | `Color or Array` | Point background color when hovered
-pointHoverBorderColor | `Color or Array` | Point border color when hovered
-pointHoverBorderWidth | `Number or Array` | Border width of point when hovered
-pointStyle | `String, Array, Image, Array` | The style of point. Options are 'circle', 'triangle', 'rect', 'rectRot', 'cross', 'crossRot', 'star', 'line', and 'dash'. If the option is an image, that image is drawn on the canvas using `drawImage`.
-showLine | `Boolean` | If false, the line is not drawn for this dataset
-spanGaps | `Boolean` | If true, lines will be drawn between points with no or null data
-steppedLine | `Boolean` | If true, the line is shown as a stepped line and 'lineTension' will be ignored
-
-An example data object using these attributes is shown below.
-```javascript
-var data = {
- labels: ["January", "February", "March", "April", "May", "June", "July"],
- datasets: [
- {
- label: "My First dataset",
- fill: false,
- lineTension: 0.1,
- backgroundColor: "rgba(75,192,192,0.4)",
- borderColor: "rgba(75,192,192,1)",
- borderCapStyle: 'butt',
- borderDash: [],
- borderDashOffset: 0.0,
- borderJoinStyle: 'miter',
- pointBorderColor: "rgba(75,192,192,1)",
- pointBackgroundColor: "#fff",
- pointBorderWidth: 1,
- pointHoverRadius: 5,
- pointHoverBackgroundColor: "rgba(75,192,192,1)",
- pointHoverBorderColor: "rgba(220,220,220,1)",
- pointHoverBorderWidth: 2,
- pointRadius: 1,
- pointHitRadius: 10,
- data: [65, 59, 80, 81, 56, 55, 40],
- spanGaps: false,
- }
- ]
-};
-```
-
-The line chart usually requires an array of labels. This labels are shown on the X axis. There must be one label for each data point. More labels than datapoints are allowed, in which case the line ends at the last data point.
-The data for line charts is broken up into an array of datasets. Each dataset has a colour for the fill, a colour for the line and colours for the points and strokes of the points. These colours are strings just like CSS. You can use RGBA, RGB, HEX or HSL notation.
-
-The label key on each dataset is optional, and can be used when generating a scale for the chart.
-
-When `spanGaps` is set to true, the gaps between points in sparse datasets are filled in. By default, it is off.
-
-### Data Points
-
-The data passed to the chart can be passed in two formats. The most common method is to pass the data array as an array of numbers. In this case, the `data.labels` array must be specified and must contain a label for each point or, in the case of labels to be displayed over multiple lines an array of labels (one for each line) i.e `[["June","2015"], "July"]`.
-
-The alternate is used for sparse datasets. Data is specified using an object containing `x` and `y` properties. This is used for scatter charts as documented below.
-
-### Scatter Line Charts
-
-Scatter line charts can be created by changing the X axis to a linear axis. To use a scatter chart, data must be passed as objects containing X and Y properties. The example below creates a scatter chart with 3 points.
-
-```javascript
-var scatterChart = new Chart(ctx, {
- type: 'line',
- data: {
- datasets: [{
- label: 'Scatter Dataset',
- data: [{
- x: -10,
- y: 0
- }, {
- x: 0,
- y: 10
- }, {
- x: 10,
- y: 5
- }]
- }]
- },
- options: {
- scales: {
- xAxes: [{
- type: 'linear',
- position: 'bottom'
- }]
- }
- }
-});
-```
-
-### Chart Options
-
-These are the customisation options specific to Line charts. These options are merged with the [global chart configuration options](#chart-configuration-global-configuration), and form the options of the chart.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-showLines | Boolean | true | If false, the lines between points are not drawn
-spanGaps | Boolean | false | If true, NaN data does not break the line
-
-You can override these for your `Chart` instance by passing a member `options` into the `Line` method.
-
-For example, we could have a line chart display without an X axis by doing the following. The config merge is smart enough to handle arrays so that you do not need to specify all axis settings to change one thing.
-
-```javascript
-new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- scales: {
- xAxes: [{
- display: false
- }]
- }
- }
-});
-```
-
-We can also change these defaults values for each Line type that is created, this object is available at `Chart.defaults.line`.
-
-### Stacked Charts
-
-Stacked area charts can be created by setting the Y axis to a stacked configuration. The following example would have stacked lines.
-
-```javascript
-var stackedLine = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- scales: {
- yAxes: [{
- stacked: true
- }]
- }
- }
-});
-```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/04-Bar-Chart.md b/contao/assets/chartjs/docs/04-Bar-Chart.md
deleted file mode 100644
index 777acc7..0000000
--- a/contao/assets/chartjs/docs/04-Bar-Chart.md
+++ /dev/null
@@ -1,173 +0,0 @@
----
-title: Bar Chart
-anchor: bar-chart
----
-
-### Introduction
-A bar chart is a way of showing data as bars.
-
-It is sometimes used to show trend data, and the comparison of multiple data sets side by side.
-
-
-
-
-
-### Example Usage
-```javascript
-var myBarChart = new Chart(ctx, {
- type: 'bar',
- data: data,
- options: options
-});
-```
-
-Or if you want horizontal bars.
-
-```javascript
-var myBarChart = new Chart(ctx, {
- type: 'horizontalBar',
- data: data,
- options: options
-});
-```
-
-### Dataset Structure
-The following options can be included in a bar chart dataset to configure options for that specific dataset.
-
-Some properties can be specified as an array. If these are set to an array value, the first value applies to the first bar, the second value to the second bar, and so on.
-
-Property | Type | Usage
---- | --- | ---
-data | `Array` | The data to plot as bars
-label | `String` | The label for the dataset which appears in the legend and tooltips
-xAxisID | `String` | The ID of the x axis to plot this dataset on
-yAxisID | `String` | The ID of the y axis to plot this dataset on
-backgroundColor | `Color or Array` | The fill color of the bars. See [Colors](#chart-configuration-colors)
-borderColor | `Color or Array` | Bar border color
-borderWidth | `Number or Array` | Border width of bar in pixels
-borderSkipped | `String or Array` | Which edge to skip drawing the border for. Options are 'bottom', 'left', 'top', and 'right'
-hoverBackgroundColor | `Color or Array` | Bar background color when hovered
-hoverBorderColor | `Color or Array` | Bar border color when hovered
-hoverBorderWidth | `Number or Array` | Border width of bar when hovered
-
-An example data object using these attributes is shown below.
-
-```javascript
-var data = {
- labels: ["January", "February", "March", "April", "May", "June", "July"],
- datasets: [
- {
- label: "My First dataset",
- backgroundColor: [
- 'rgba(255, 99, 132, 0.2)',
- 'rgba(54, 162, 235, 0.2)',
- 'rgba(255, 206, 86, 0.2)',
- 'rgba(75, 192, 192, 0.2)',
- 'rgba(153, 102, 255, 0.2)',
- 'rgba(255, 159, 64, 0.2)'
- ],
- borderColor: [
- 'rgba(255,99,132,1)',
- 'rgba(54, 162, 235, 1)',
- 'rgba(255, 206, 86, 1)',
- 'rgba(75, 192, 192, 1)',
- 'rgba(153, 102, 255, 1)',
- 'rgba(255, 159, 64, 1)'
- ],
- borderWidth: 1,
- data: [65, 59, 80, 81, 56, 55, 40],
- }
- ]
-};
-```
-The bar chart has the a very similar data structure to the line chart, and has an array of datasets, each with colours and an array of data.
-We have an array of labels too for display. In the example, we are showing the same data as the previous line chart example.
-
-### Chart Options
-
-These are the customisation options specific to Bar charts. These options are merged with the [global chart configuration options](#global-chart-configuration), and form the options of the chart.
-
-The default options for bar chart are defined in `Chart.defaults.bar`.
-
-Name | Type | Default | Description
---- |:---:| --- | ---
-*hover*.mode | String | "label" | Label's hover mode. "label" is used since the x axis displays data by the index in the dataset.
-scales | Object | - | -
-*scales*.xAxes | Array | | The bar chart officially supports only 1 x-axis but uses an array to keep the API consistent. Use a scatter chart if you need multiple x axes.
-*Options for xAxes* | | |
-type | String | "Category" | As defined in [Scales](#scales-category-scale).
-display | Boolean | true | If true, show the scale.
-id | String | "x-axis-0" | Id of the axis so that data can bind to it
-stacked | Boolean | false | If true, bars are stacked on the x-axis
-barThickness | Number | | Manually set width of each bar in pixels. If not set, the bars are sized automatically.
-categoryPercentage | Number | 0.8 | Percent (0-1) of the available width (the space between the gridlines for small datasets) for each data-point to use for the bars. [Read More](#bar-chart-barpercentage-vs-categorypercentage)
-barPercentage | Number | 0.9 | Percent (0-1) of the available width each bar should be within the category percentage. 1.0 will take the whole category width and put the bars right next to each other. [Read More](#bar-chart-barpercentage-vs-categorypercentage)
-gridLines | Object | [See Scales](#scales) |
-*gridLines*.offsetGridLines | Boolean | true | If true, the bars for a particular data point fall between the grid lines. If false, the grid line will go right down the middle of the bars.
-| | |
-*scales*.yAxes | Array | `[{ type: "linear" }]` |
-*Options for yAxes* | | |
-type | String | "linear" | As defined in [Scales](#scales-linear-scale).
-display | Boolean | true | If true, show the scale.
-id | String | "y-axis-0" | Id of the axis so that data can bind to it.
-stacked | Boolean | false | If true, bars are stacked on the y-axis
-barThickness | Number | | Manually set height of each bar in pixels. If not set, the bars are sized automatically.
-
-You can override these for your `Chart` instance by passing a second argument into the `Bar` method as an object with the keys you want to override.
-
-For example, we could have a bar chart without a stroke on each bar by doing the following:
-
-```javascript
-new Chart(ctx, {
- type: "bar",
- data: data,
- options: {
- scales: {
- xAxes: [{
- stacked: true
- }],
- yAxes: [{
- stacked: true
- }]
- }
- }
-});
-// This will create a chart with all of the default options, merged from the global config,
-// and the Bar chart defaults but this particular instance will have `stacked` set to true
-// for both x and y axes.
-```
-
-We can also change these defaults values for each Bar type that is created, this object is available at `Chart.defaults.bar`. For horizontal bars, this object is available at `Chart.defaults.horizontalBar`.
-
-The default options for horizontal bar charts are defined in `Chart.defaults.horizontalBar` and are same as those of the bar chart, but with `xAxes` and `yAxes` swapped and the following additional options.
-
-Name | Type | Default | Description
---- |:---:| --- | ---
-*Options for xAxes* | | |
-position | String | "bottom" |
-*Options for yAxes* | | |
-position | String | "left" |
-
-### barPercentage vs categoryPercentage
-
-The following shows the relationship between the bar percentage option and the category percentage option.
-
-```text
-// categoryPercentage: 1.0
-// barPercentage: 1.0
-Bar: | 1.0 | 1.0 |
-Category: | 1.0 |
-Sample: |===========|
-
-// categoryPercentage: 1.0
-// barPercentage: 0.5
-Bar: |.5| |.5|
-Category: | 1.0 |
-Sample: |==============|
-
-// categoryPercentage: 0.5
-// barPercentage: 1.0
-Bar: |1.||1.|
-Category: | .5 |
-Sample: |==============|
-```
diff --git a/contao/assets/chartjs/docs/05-Radar-Chart.md b/contao/assets/chartjs/docs/05-Radar-Chart.md
deleted file mode 100644
index f191c3a..0000000
--- a/contao/assets/chartjs/docs/05-Radar-Chart.md
+++ /dev/null
@@ -1,125 +0,0 @@
----
-title: Radar Chart
-anchor: radar-chart
----
-
-### Introduction
-A radar chart is a way of showing multiple data points and the variation between them.
-
-They are often useful for comparing the points of two or more different data sets.
-
-
-
-
-
-### Example Usage
-
-```javascript
-var myRadarChart = new Chart(ctx, {
- type: 'radar',
- data: data,
- options: options
-});
-```
-
-### Dataset Structure
-
-The following options can be included in a radar chart dataset to configure options for that specific dataset.
-
-All point* properties can be specified as an array. If these are set to an array value, the first value applies to the first point, the second value to the second point, and so on.
-
-Property | Type | Usage
---- | --- | ---
-data | `Array` | The data to plot in a line
-label | `String` | The label for the dataset which appears in the legend and tooltips
-fill | `Boolean` | If true, fill the area under the line
-lineTension | `Number` | Bezier curve tension of the line. Set to 0 to draw straightlines. *Note* This was renamed from 'tension' but the old name still works.
-backgroundColor | `Color` | The fill color under the line. See [Colors](#chart-configuration-colors)
-borderWidth | `Number` | The width of the line in pixels
-borderColor | `Color` | The color of the line.
-borderCapStyle | `String` | Cap style of the line. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap)
-borderDash | `Array` | Length and spacing of dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
-borderDashOffset | `Number` | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
-borderJoinStyle | `String` | Line joint style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
-pointBorderColor | `Color or Array` | The border color for points.
-pointBackgroundColor | `Color or Array` | The fill color for points
-pointBorderWidth | `Number or Array` | The width of the point border in pixels
-pointRadius | `Number or Array` | The radius of the point shape. If set to 0, nothing is rendered.
-pointHoverRadius | `Number or Array` | The radius of the point when hovered
-hitRadius | `Number or Array` | The pixel size of the non-displayed point that reacts to mouse events
-pointHoverBackgroundColor | `Color or Array` | Point background color when hovered
-pointHoverBorderColor | `Color or Array` | Point border color when hovered
-pointHoverBorderWidth | `Number or Array` | Border width of point when hovered
-pointStyle | `String or Array` | The style of point. Options include 'circle', 'triangle', 'rect', 'rectRot', 'cross', 'crossRot', 'star', 'line', and 'dash'
-
-An example data object using these attributes is shown below.
-
-```javascript
-var data = {
- labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"],
- datasets: [
- {
- label: "My First dataset",
- backgroundColor: "rgba(179,181,198,0.2)",
- borderColor: "rgba(179,181,198,1)",
- pointBackgroundColor: "rgba(179,181,198,1)",
- pointBorderColor: "#fff",
- pointHoverBackgroundColor: "#fff",
- pointHoverBorderColor: "rgba(179,181,198,1)",
- data: [65, 59, 90, 81, 56, 55, 40]
- },
- {
- label: "My Second dataset",
- backgroundColor: "rgba(255,99,132,0.2)",
- borderColor: "rgba(255,99,132,1)",
- pointBackgroundColor: "rgba(255,99,132,1)",
- pointBorderColor: "#fff",
- pointHoverBackgroundColor: "#fff",
- pointHoverBorderColor: "rgba(255,99,132,1)",
- data: [28, 48, 40, 19, 96, 27, 100]
- }
- ]
-};
-```
-For a radar chart, to provide context of what each point means, we include an array of strings that show around each point in the chart.
-For the radar chart data, we have an array of datasets. Each of these is an object, with a fill colour, a stroke colour, a colour for the fill of each point, and a colour for the stroke of each point. We also have an array of data values.
-The label key on each dataset is optional, and can be used when generating a scale for the chart.
-
-
-### Chart Options
-
-These are the customisation options specific to Radar charts. These options are merged with the [global chart configuration options](#global-chart-configuration), and form the options of the chart.
-
-The default options for radar chart are defined in `Chart.defaults.radar`.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-scale | Object | [See Scales](#scales) and [Defaults for Radial Linear Scale](#scales-radial-linear-scale) | Options for the one scale used on the chart. Use this to style the ticks, labels, and grid lines.
-*scale*.type | String |"radialLinear" | As defined in ["Radial Linear"](#scales-radial-linear-scale).
-*elements*.line | Object | | Options for all line elements used on the chart, as defined in the global elements, duplicated here to show Radar chart specific defaults.
-*elements.line*.lineTension | Number | 0 | Tension exhibited by lines when calculating splineCurve. Setting to 0 creates straight lines.
-startAngle | Number | 0 | The number of degrees to rotate the chart clockwise.
-
-You can override these for your `Chart` instance by passing a second argument into the `Radar` method as an object with the keys you want to override.
-
-For example, we could have a radar chart without a point for each on piece of data by doing the following:
-
-```javascript
-new Chart(ctx, {
- type: "radar",
- data: data,
- options: {
- scale: {
- reverse: true,
- ticks: {
- beginAtZero: true
- }
- }
- }
-});
-// This will create a chart with all of the default options, merged from the global config,
-// and the Radar chart defaults but this particular instance's scale will be reversed as
-// well as the ticks beginning at zero.
-```
-
-We can also change these defaults values for each Radar type that is created, this object is available at `Chart.defaults.radar`.
diff --git a/contao/assets/chartjs/docs/06-Polar-Area-Chart.md b/contao/assets/chartjs/docs/06-Polar-Area-Chart.md
deleted file mode 100644
index 4f2d896..0000000
--- a/contao/assets/chartjs/docs/06-Polar-Area-Chart.md
+++ /dev/null
@@ -1,109 +0,0 @@
----
-title: Polar Area Chart
-anchor: polar-area-chart
----
-### Introduction
-Polar area charts are similar to pie charts, but each segment has the same angle - the radius of the segment differs depending on the value.
-
-This type of chart is often useful when we want to show a comparison data similar to a pie chart, but also show a scale of values for context.
-
-
-
-
-
-### Example Usage
-
-```javascript
-new Chart(ctx, {
- data: data,
- type: 'polarArea',
- options: options
-});
-```
-
-### Dataset Structure
-
-The following options can be included in a polar area chart dataset to configure options for that specific dataset.
-
-Some properties are specified as arrays. The first value applies to the first bar, the second value to the second bar, and so on.
-
-Property | Type | Usage
---- | --- | ---
-data | `Array` | The data to plot as arcs
-label | `String` | The label for the dataset which appears in the legend and tooltips
-backgroundColor | `Array` | The fill color of the arcs. See [Colors](#chart-configuration-colors)
-borderColor | `Array` | Arc border color
-borderWidth | `Array` | Border width of arcs in pixels
-hoverBackgroundColor | `Array` | Arc background color when hovered
-hoverBorderColor | `Array` | Arc border color when hovered
-hoverBorderWidth | `Array` | Border width of arc when hovered
-
-An example data object using these attributes is shown below.
-
-```javascript
-var data = {
- datasets: [{
- data: [
- 11,
- 16,
- 7,
- 3,
- 14
- ],
- backgroundColor: [
- "#FF6384",
- "#4BC0C0",
- "#FFCE56",
- "#E7E9ED",
- "#36A2EB"
- ],
- label: 'My dataset' // for legend
- }],
- labels: [
- "Red",
- "Green",
- "Yellow",
- "Grey",
- "Blue"
- ]
-};
-```
-As you can see, for the chart data you pass in an array of objects, with a value and a colour. The value attribute should be a number, while the color attribute should be a string. Similar to CSS, for this string you can use HEX notation, RGB, RGBA or HSL.
-
-### Chart Options
-
-These are the customisation options specific to Polar Area charts. These options are merged with the [global chart configuration options](#global-chart-configuration), and form the options of the chart.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-startAngle | Number | -0.5 * Math.PI | Sets the starting angle for the first item in a dataset
-scale | Object | [See Scales](#scales) and [Defaults for Radial Linear Scale](#scales-radial-linear-scale) | Options for the one scale used on the chart. Use this to style the ticks, labels, and grid.
-*scale*.type | String |"radialLinear" | As defined in ["Radial Linear"](#scales-radial-linear-scale).
-*scale*.lineArc | Boolean | true | When true, lines are circular.
-*animation*.animateRotate | Boolean |true | If true, will animate the rotation of the chart.
-*animation*.animateScale | Boolean | true | If true, will animate scaling the chart.
-*legend*.*labels*.generateLabels | Function | `function(data) {} ` | Returns labels for each the legend
-*legend*.onClick | Function | function(event, legendItem) {} ` | Handles clicking an individual legend item
-legendCallback | Function | `function(chart) ` | Generates the HTML legend via calls to `generateLegend`
-
-You can override these for your `Chart` instance by passing a second argument into the `PolarArea` method as an object with the keys you want to override.
-
-For example, we could have a polar area chart with a black stroke on each segment like so:
-
-```javascript
-new Chart(ctx, {
- data: data,
- type: "polarArea",
- options: {
- elements: {
- arc: {
- borderColor: "#000000"
- }
- }
- }
-});
-// This will create a chart with all of the default options, merged from the global config,
-// and the PolarArea chart defaults but this particular instance will have `elements.arc.borderColor` set to `"#000000"`.
-```
-
-We can also change these defaults values for each PolarArea type that is created, this object is available at `Chart.defaults.polarArea`.
diff --git a/contao/assets/chartjs/docs/07-Pie-Doughnut-Chart.md b/contao/assets/chartjs/docs/07-Pie-Doughnut-Chart.md
deleted file mode 100644
index 0b2cc11..0000000
--- a/contao/assets/chartjs/docs/07-Pie-Doughnut-Chart.md
+++ /dev/null
@@ -1,113 +0,0 @@
----
-title: Pie & Doughnut Charts
-anchor: doughnut-pie-chart
----
-### Introduction
-Pie and doughnut charts are probably the most commonly used charts there are. They are divided into segments, the arc of each segment shows the proportional value of each piece of data.
-
-They are excellent at showing the relational proportions between data.
-
-Pie and doughnut charts are effectively the same class in Chart.js, but have one different default value - their `cutoutPercentage`. This equates what percentage of the inner should be cut out. This defaults to `0` for pie charts, and `50` for doughnuts.
-
-They are also registered under two aliases in the `Chart` core. Other than their different default value, and different alias, they are exactly the same.
-
-
-
-
-
-
-
-
-
-
-### Example Usage
-
-```javascript
-// For a pie chart
-var myPieChart = new Chart(ctx,{
- type: 'pie',
- data: data,
- options: options
-});
-```
-
-```javascript
-// And for a doughnut chart
-var myDoughnutChart = new Chart(ctx, {
- type: 'doughnut',
- data: data,
- options: options
-});
-```
-
-### Dataset Structure
-
-Property | Type | Usage
---- | --- | ---
-data | `Array` | The data to plot as arcs
-label | `String` | The label for the dataset which appears in the legend and tooltips
-backgroundColor | `Array` | The fill color of the arcs. See [Colors](#chart-configuration-colors)
-borderColor | `Array` | Arc border color
-borderWidth | `Array` | Border width of arcs in pixels
-hoverBackgroundColor | `Array` | Arc background color when hovered
-hoverBorderColor | `Array` | Arc border color when hovered
-hoverBorderWidth | `Array` | Border width of arc when hovered
-
-An example data object using these attributes is shown below.
-
-```javascript
-var data = {
- labels: [
- "Red",
- "Blue",
- "Yellow"
- ],
- datasets: [
- {
- data: [300, 50, 100],
- backgroundColor: [
- "#FF6384",
- "#36A2EB",
- "#FFCE56"
- ],
- hoverBackgroundColor: [
- "#FF6384",
- "#36A2EB",
- "#FFCE56"
- ]
- }]
-};
-```
-
-For a pie chart, datasets need to contain an array of data points. The data points should be a number, Chart.js will total all of the numbers and calculate the relative proportion of each. You can also add an array of background colors. The color attributes should be a string. Similar to CSS, for this string you can use HEX notation, RGB, RGBA or HSL.
-
-### Chart Options
-
-These are the customisation options specific to Pie & Doughnut charts. These options are merged with the [global chart configuration options](#global-chart-configuration), and form the options of the chart.
-
-Name | Type | Default | Description
---- | --- | --- | ---
-cutoutPercentage | Number | 50 - for doughnut, 0 - for pie | The percentage of the chart that is cut out of the middle.
-rotation | Number | -0.5 * Math.PI | Starting angle to draw arcs from
-circumference | Number | 2 * Math.PI | Sweep to allow arcs to cover
-*animation*.animateRotate | Boolean |true | If true, will animate the rotation of the chart.
-*animation*.animateScale | Boolean | false | If true, will animate scaling the Doughnut from the centre.
-*legend*.*labels*.generateLabels | Function | `function(chart) {} ` | Returns a label for each item to be displayed on the legend.
-*legend*.onClick | Function | function(event, legendItem) {} ` | Handles clicking an individual legend item
-
-You can override these for your `Chart` instance by passing a second argument into the `Doughnut` method as an object with the keys you want to override.
-
-For example, we could have a doughnut chart that animates by scaling out from the centre like so:
-
-```javascript
-new Chart(ctx,{
- type:"doughnut",
- animation:{
- animateScale:true
- }
-});
-// This will create a chart with all of the default options, merged from the global config,
-// and the Doughnut chart defaults but this particular instance will have `animateScale` set to `true`.
-```
-
-We can also change these default values for each Doughnut type that is created, this object is available at `Chart.defaults.doughnut`. Pie charts also have a clone of these defaults available to change at `Chart.defaults.pie`, with the only difference being `cutoutPercentage` being set to 0.
diff --git a/contao/assets/chartjs/docs/08-Bubble-Chart.md b/contao/assets/chartjs/docs/08-Bubble-Chart.md
deleted file mode 100644
index 59b8b77..0000000
--- a/contao/assets/chartjs/docs/08-Bubble-Chart.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-title: Bubble Chart
-anchor: bubble-chart
----
-### Introduction
-A bubble chart is used to display three dimensions of data at the same time. The location of the bubble is determined by the first two dimensions and the corresponding horizontal and vertical axes. The third dimension is represented by the size of the individual bubbles.
-
-
-
-
-
-
-### Example Usage
-
-```javascript
-// For a bubble chart
-var myBubbleChart = new Chart(ctx,{
- type: 'bubble',
- data: data,
- options: options
-});
-```
-
-### Dataset Structure
-
-Property | Type | Usage
---- | --- | ---
-data | `Array` | The data to plot as bubbles. See [Data format](#bubble-chart-data-format)
-label | `String` | The label for the dataset which appears in the legend and tooltips
-backgroundColor | `Color Array` | The fill color of the bubbles. See [Colors](#chart-configuration-colors)
-borderColor | `Color or Array` | The stroke color of the bubbles.
-borderWidth | `Number or Array` | The stroke width of bubble in pixels.
-hoverBackgroundColor | `Color or Array` | The fill color of the bubbles when hovered.
-hoverBorderColor | `Color or Array` | The stroke color of the bubbles when hovered.
-hoverBorderWidth | `Number or Array` | The stroke width of the bubbles when hovered.
-hoverRadius | `Number or Array` | Additional radius to add to data radius on hover.
-
-An example data object using these attributes is shown below. This example creates a single dataset with 2 different bubbles.
-
-```javascript
-var data = {
- datasets: [
- {
- label: 'First Dataset',
- data: [
- {
- x: 20,
- y: 30,
- r: 15
- },
- {
- x: 40,
- y: 10,
- r: 10
- }
- ],
- backgroundColor:"#FF6384",
- hoverBackgroundColor: "#FF6384",
- }]
-};
-```
-
-### Data Object
-
-Data for the bubble chart is passed in the form of an object. The object must implement the following interface. It is important to note that the radius property, `r` is **not** scaled by the chart. It is the raw radius in pixels of the bubble that is drawn on the canvas.
-
-```javascript
-{
- // X Value
- x: ,
-
- // Y Value
- y: ,
-
- // Radius of bubble. This is not scaled.
- r:
-}
-```
-
-### Chart Options
-
-The bubble chart has no unique configuration options. To configure options common to all of the bubbles, the point element options are used.
-
-For example, to give all bubbles a 1px wide black border, the following options would be used.
-
-```javascript
-new Chart(ctx,{
- type:"bubble",
- options: {
- elements: {
- points: {
- borderWidth: 1,
- borderColor: 'rgb(0, 0, 0)'
- }
- }
- }
-});
-```
-
-We can also change the default values for the Bubble chart type. Doing so will give all bubble charts created after this point the new defaults. The default configuration for the bubble chart can be accessed at `Chart.defaults.bubble`.
diff --git a/contao/assets/chartjs/docs/09-Advanced.md b/contao/assets/chartjs/docs/09-Advanced.md
deleted file mode 100644
index 062bf59..0000000
--- a/contao/assets/chartjs/docs/09-Advanced.md
+++ /dev/null
@@ -1,460 +0,0 @@
----
-title: Advanced usage
-anchor: advanced-usage
----
-
-
-### Prototype Methods
-
-For each chart, there are a set of global prototype methods on the shared `ChartType` which you may find useful. These are available on all charts created with Chart.js, but for the examples, let's use a line chart we've made.
-
-```javascript
-// For example:
-var myLineChart = new Chart(ctx, config);
-```
-
-#### .destroy()
-
-Use this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js.
-This must be called before the canvas is reused for a new chart.
-
-```javascript
-// Destroys a specific chart instance
-myLineChart.destroy();
-```
-
-#### .update(duration, lazy)
-
-Triggers an update of the chart. This can be safely called after replacing the entire data object. This will update all scales, legends, and then re-render the chart.
-
-```javascript
-// duration is the time for the animation of the redraw in milliseconds
-// lazy is a boolean. if true, the animation can be interrupted by other animations
-myLineChart.data.datasets[0].data[2] = 50; // Would update the first dataset's value of 'March' to be 50
-myLineChart.update(); // Calling update now animates the position of March from 90 to 50.
-```
-
-#### .reset()
-
-Reset the chart to it's state before the initial animation. A new animation can then be triggered using `update`.
-
-```javascript
-myLineChart.reset();
-```
-
-#### .render(duration, lazy)
-
-Triggers a redraw of all chart elements. Note, this does not update elements for new data. Use `.update()` in that case.
-
-```javascript
-// duration is the time for the animation of the redraw in milliseconds
-// lazy is a boolean. if true, the animation can be interrupted by other animations
-myLineChart.render(duration, lazy);
-```
-
-#### .stop()
-
-Use this to stop any current animation loop. This will pause the chart during any current animation frame. Call `.render()` to re-animate.
-
-```javascript
-// Stops the charts animation loop at its current frame
-myLineChart.stop();
-// => returns 'this' for chainability
-```
-
-#### .resize()
-
-Use this to manually resize the canvas element. This is run each time the canvas container is resized, but you can call this method manually if you change the size of the canvas nodes container element.
-
-```javascript
-// Resizes & redraws to fill its container element
-myLineChart.resize();
-// => returns 'this' for chainability
-```
-
-#### .clear()
-
-Will clear the chart canvas. Used extensively internally between animation frames, but you might find it useful.
-
-```javascript
-// Will clear the canvas that myLineChart is drawn on
-myLineChart.clear();
-// => returns 'this' for chainability
-```
-
-#### .toBase64Image()
-
-This returns a base 64 encoded string of the chart in it's current state.
-
-```javascript
-myLineChart.toBase64Image();
-// => returns png data url of the image on the canvas
-```
-
-#### .generateLegend()
-
-Returns an HTML string of a legend for that chart. The legend is generated from the `legendCallback` in the options.
-
-```javascript
-myLineChart.generateLegend();
-// => returns HTML string of a legend for this chart
-```
-
-#### .getElementAtEvent(e)
-
-Calling `getElementAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the single element at the event position. If there are multiple items within range, only the first is returned
-
-```javascript
-myLineChart.getElementAtEvent(e);
-// => returns the first element at the event point.
-```
-
-#### .getElementsAtEvent(e)
-
-Looks for the element under the event point, then returns all elements at the same data index. This is used internally for 'label' mode highlighting.
-
-Calling `getElementsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event.
-
-```javascript
-canvas.onclick = function(evt){
- var activePoints = myLineChart.getElementsAtEvent(evt);
- // => activePoints is an array of points on the canvas that are at the same position as the click event.
-};
-```
-
-This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application.
-
-#### .getDatasetAtEvent(e)
-
-Looks for the element under the event point, then returns all elements from that dataset. This is used internally for 'dataset' mode highlighting
-
-```javascript
-myLineChart.getDatasetAtEvent(e);
-// => returns an array of elements
-```
-
-#### .getDatasetMeta(index)
-
-Looks for the dataset that matches the current index and returns that metadata. This returned data has all of the metadata that is used to construct the chart.
-
-The `data` property of the metadata will contain information about each point, rectangle, etc. depending on the chart type.
-
-Extensive examples of usage are available in the [Chart.js tests](https://github.com/chartjs/Chart.js/tree/master/test).
-
-```javascript
-var meta = myChart.getDatasetMeta(0);
-var x = meta.data[0]._model.x
-```
-
-### External Tooltips
-
-You can enable custom tooltips in the global or chart configuration like so:
-
-```javascript
-var myPieChart = new Chart(ctx, {
- type: 'pie',
- data: data,
- options: {
- tooltips: {
- custom: function(tooltip) {
- // tooltip will be false if tooltip is not visible or should be hidden
- if (!tooltip) {
- return;
- }
-
- // Otherwise, tooltip will be an object with all tooltip properties like:
-
- // tooltip.caretSize
- // tooltip.caretPadding
- // tooltip.chart
- // tooltip.cornerRadius
- // tooltip.fillColor
- // tooltip.font...
- // tooltip.text
- // tooltip.x
- // tooltip.y
- // tooltip.caretX
- // tooltip.caretY
- // etc...
- }
- }
- }
-});
-```
-
-See `sample/line-customTooltips.html` for examples on how to get started.
-
-### Writing New Scale Types
-
-Starting with Chart.js 2.0 scales can be individually extended. Scales should always derive from Chart.Scale.
-
-```javascript
-var MyScale = Chart.Scale.extend({
- /* extensions ... */
-});
-
-// MyScale is now derived from Chart.Scale
-```
-
-Once you have created your scale class, you need to register it with the global chart object so that it can be used. A default config for the scale may be provided when registering the constructor. The first parameter to the register function is a string key that is used later to identify which scale type to use for a chart.
-
-```javascript
-Chart.scaleService.registerScaleType('myScale', MyScale, defaultConfigObject);
-```
-
-To use the new scale, simply pass in the string key to the config when creating a chart.
-
-```javascript
-var lineChart = new Chart(ctx, {
- data: data,
- type: 'line',
- options: {
- scales: {
- yAxes: [{
- type: 'myScale' // this is the same key that was passed to the registerScaleType function
- }]
- }
- }
-})
-```
-
-#### Scale Properties
-
-Scale instances are given the following properties during the fitting process.
-
-```javascript
-{
- left: Number, // left edge of the scale bounding box
- right: Number, // right edge of the bounding box'
- top: Number,
- bottom: Number,
- width: Number, // the same as right - left
- height: Number, // the same as bottom - top
-
- // Margin on each side. Like css, this is outside the bounding box.
- margins: {
- left: Number,
- right: Number,
- top: Number,
- bottom: Number,
- },
-
- // Amount of padding on the inside of the bounding box (like CSS)
- paddingLeft: Number,
- paddingRight: Number,
- paddingTop: Number,
- paddingBottom: Number,
-}
-```
-
-#### Scale Interface
-To work with Chart.js, custom scale types must implement the following interface.
-
-```javascript
-{
- // Determines the data limits. Should set this.min and this.max to be the data max/min
- determineDataLimits: function() {},
-
- // Generate tick marks. this.chart is the chart instance. The data object can be accessed as this.chart.data
- // buildTicks() should create a ticks array on the axis instance, if you intend to use any of the implementations from the base class
- buildTicks: function() {},
-
- // Get the value to show for the data at the given index of the the given dataset, ie this.chart.data.datasets[datasetIndex].data[index]
- getLabelForIndex: function(index, datasetIndex) {},
-
- // Get the pixel (x coordinate for horizontal axis, y coordinate for vertical axis) for a given value
- // @param index: index into the ticks array
- // @param includeOffset: if true, get the pixel halway between the given tick and the next
- getPixelForTick: function(index, includeOffset) {},
-
- // Get the pixel (x coordinate for horizontal axis, y coordinate for vertical axis) for a given value
- // @param value : the value to get the pixel for
- // @param index : index into the data array of the value
- // @param datasetIndex : index of the dataset the value comes from
- // @param includeOffset : if true, get the pixel halway between the given tick and the next
- getPixelForValue: function(value, index, datasetIndex, includeOffset) {}
-
- // Get the value for a given pixel (x coordinate for horizontal axis, y coordinate for vertical axis)
- // @param pixel : pixel value
- getValueForPixel: function(pixel) {}
-}
-```
-
-Optionally, the following methods may also be overwritten, but an implementation is already provided by the `Chart.Scale` base class.
-
-```javascript
- // Transform the ticks array of the scale instance into strings. The default implementation simply calls this.options.ticks.callback(numericalTick, index, ticks);
- convertTicksToLabels: function() {},
-
- // Determine how much the labels will rotate by. The default implementation will only rotate labels if the scale is horizontal.
- calculateTickRotation: function() {},
-
- // Fits the scale into the canvas.
- // this.maxWidth and this.maxHeight will tell you the maximum dimensions the scale instance can be. Scales should endeavour to be as efficient as possible with canvas space.
- // this.margins is the amount of space you have on either side of your scale that you may expand in to. This is used already for calculating the best label rotation
- // You must set this.minSize to be the size of your scale. It must be an object containing 2 properties: width and height.
- // You must set this.width to be the width and this.height to be the height of the scale
- fit: function() {},
-
- // Draws the scale onto the canvas. this.(left|right|top|bottom) will have been populated to tell you the area on the canvas to draw in
- // @param chartArea : an object containing four properties: left, right, top, bottom. This is the rectangle that lines, bars, etc will be drawn in. It may be used, for example, to draw grid lines.
- draw: function(chartArea) {},
-```
-
-The Core.Scale base class also has some utility functions that you may find useful.
-```javascript
-{
- // Returns true if the scale instance is horizontal
- isHorizontal: function() {},
-
- // Get the correct value from the value from this.chart.data.datasets[x].data[]
- // If dataValue is an object, returns .x or .y depending on the return of isHorizontal()
- // If the value is undefined, returns NaN
- // Otherwise returns the value.
- // Note that in all cases, the returned value is not guaranteed to be a Number
- getRightValue: function(dataValue) {},
-}
-```
-
-### Writing New Chart Types
-
-Chart.js 2.0 introduces the concept of controllers for each dataset. Like scales, new controllers can be written as needed.
-
-```javascript
-Chart.controllers.MyType = Chart.DatasetController.extend({
-
-});
-
-
-// Now we can create a new instance of our chart, using the Chart.js API
-new Chart(ctx, {
- // this is the string the constructor was registered at, ie Chart.controllers.MyType
- type: 'MyType',
- data: data,
- options: options
-});
-```
-
-#### Dataset Controller Interface
-
-Dataset controllers must implement the following interface.
-
-```javascript
-{
- // Create elements for each piece of data in the dataset. Store elements in an array on the dataset as dataset.metaData
- addElements: function() {},
-
- // Create a single element for the data at the given index and reset its state
- addElementAndReset: function(index) {},
-
- // Draw the representation of the dataset
- // @param ease : if specified, this number represents how far to transition elements. See the implementation of draw() in any of the provided controllers to see how this should be used
- draw: function(ease) {},
-
- // Remove hover styling from the given element
- removeHoverStyle: function(element) {},
-
- // Add hover styling to the given element
- setHoverStyle: function(element) {},
-
- // Update the elements in response to new data
- // @param reset : if true, put the elements into a reset state so they can animate to their final values
- update: function(reset) {},
-}
-```
-
-The following methods may optionally be overridden by derived dataset controllers
-```javascript
-{
- // Initializes the controller
- initialize: function(chart, datasetIndex) {},
-
- // Ensures that the dataset represented by this controller is linked to a scale. Overridden to helpers.noop in the polar area and doughnut controllers as these
- // chart types using a single scale
- linkScales: function() {},
-
- // Called by the main chart controller when an update is triggered. The default implementation handles the number of data points changing and creating elements appropriately.
- buildOrUpdateElements: function() {}
-}
-```
-
-### Extending Existing Chart Types
-
-Extending or replacing an existing controller type is easy. Simply replace the constructor for one of the built in types with your own.
-
-The built in controller types are:
-* `Chart.controllers.line`
-* `Chart.controllers.bar`
-* `Chart.controllers.radar`
-* `Chart.controllers.doughnut`
-* `Chart.controllers.polarArea`
-* `Chart.controllers.bubble`
-
-#### Bar Controller
-The bar controller has a special property that you should be aware of. To correctly calculate the width of a bar, the controller must determine the number of datasets that map to bars. To do this, the bar controller attaches a property `bar` to the dataset during initialization. If you are creating a replacement or updated bar controller, you should do the same. This will ensure that charts with regular bars and your new derived bars will work seamlessly.
-
-### Creating Plugins
-
-Starting with v2.1.0, you can create plugins for chart.js. To register your plugin, simply call `Chart.plugins.register` and pass your plugin in.
-Plugins will be called at the following times
-* Start of initialization
-* End of initialization
-* Start of update
-* After the chart scales have calculated
-* Start of datasets update
-* End of datasets update
-* End of update (before render occurs)
-* Start of draw
-* End of draw
-* Before datasets draw
-* After datasets draw
-* Resize
-* Before an animation is started
-
-Plugins should derive from Chart.PluginBase and implement the following interface
-```javascript
-{
- beforeInit: function(chartInstance) { },
- afterInit: function(chartInstance) { },
-
- resize: function(chartInstance, newChartSize) { },
-
- beforeUpdate: function(chartInstance) { },
- afterScaleUpdate: function(chartInstance) { }
- beforeDatasetsUpdate: function(chartInstance) { }
- afterDatasetsUpdate: function(chartInstance) { }
- afterUpdate: function(chartInstance) { },
-
- // This is called at the start of a render. It is only called once, even if the animation will run for a number of frames. Use beforeDraw or afterDraw
- // to do something on each animation frame
- beforeRender: function(chartInstance) { },
-
- // Easing is for animation
- beforeDraw: function(chartInstance, easing) { },
- afterDraw: function(chartInstance, easing) { },
- // Before the datasets are drawn but after scales are drawn
- beforeDatasetsDraw: function(chartInstance, easing) { },
- afterDatasetsDraw: function(chartInstance, easing) { },
-
- destroy: function(chartInstance) { }
-}
-```
-
-### Building Chart.js
-
-Chart.js uses gulp to build the library into a single JavaScript file.
-
-Firstly, we need to ensure development dependencies are installed. With node and npm installed, after cloning the Chart.js repo to a local directory, and navigating to that directory in the command line, we can run the following:
-
-```bash
-npm install
-npm install -g gulp
-```
-
-This will install the local development dependencies for Chart.js, along with a CLI for the JavaScript task runner gulp .
-
-Now, we can run the `gulp build` task.
-
-```bash
-gulp build
-```
diff --git a/contao/assets/chartjs/docs/10-Notes.md b/contao/assets/chartjs/docs/10-Notes.md
deleted file mode 100644
index fd2125e..0000000
--- a/contao/assets/chartjs/docs/10-Notes.md
+++ /dev/null
@@ -1,110 +0,0 @@
----
-title: Notes
-anchor: notes
----
-### Previous versions
-
-Version 2 has a completely different API than earlier versions.
-
-Most earlier version options have current equivalents or are the same.
-
-Please use the documentation that is available on [chartjs.org](http://www.chartjs.org/docs/) for the current version of Chart.js.
-
-Please note - documentation for previous versions are available on the GitHub repo.
-
-- [1.x Documentation](https://github.com/chartjs/Chart.js/tree/v1.1.1/docs)
-
-### Browser support
-
-Chart.js offers support for all browsers where canvas is supported.
-
-Browser support for the canvas element is available in all modern & major mobile browsers (http://caniuse.com/#feat=canvas) .
-
-Thanks to BrowserStack for allowing our team to test on thousands of browsers.
-
-
-### Bugs & issues
-
-Please report these on the GitHub page - at github.com/chartjs/Chart.js . If you could include a link to a simple jsbin or similar to demonstrate the issue, that'd be really helpful.
-
-
-### Contributing
-
-New contributions to the library are welcome, but we ask that you please follow these guidelines:
-
-- Use tabs for indentation, not spaces.
-- Only change the individual files in `/src`.
-- Check that your code will pass `eslint` code standards, `gulp lint` will run this for you.
-- Check that your code will pass tests, `gulp test` will run tests for you.
-- Keep pull requests concise, and document new functionality in the relevant `.md` file.
-- Consider whether your changes are useful for all users, or if creating a Chart.js plugin would be more appropriate.
-
-### License
-
-Chart.js is open source and available under the MIT license .
-
-### Charting Library Comparison
-
-Library Features
-
-| Feature | Chart.js | D3 | HighCharts | Chartist |
-| ------- | -------- | --- | ---------- | -------- |
-| Completely Free | ✓ | ✓ | | ✓ |
-| Canvas | ✓ | | | |
-| SVG | | ✓ | ✓ | ✓ |
-| Built-in Charts | ✓ | | ✓ | ✓ |
-| 8+ Chart Types | ✓ | ✓ | ✓ | |
-| Extendable to Custom Charts | ✓ | ✓ | | |
-| Supports Modern Browsers | ✓ | ✓ | ✓ | ✓ |
-| Extensive Documentation | ✓ | ✓ | ✓ | ✓ |
-| Open Source | ✓ | ✓ | ✓ | ✓ |
-
-Built in Chart Types
-
-| Type | Chart.js | HighCharts | Chartist |
-| ---- | -------- | ---------- | -------- |
-| Combined Types | ✓ | ✓ | |
-| Line | ✓ | ✓ | ✓ |
-| Bar | ✓ | ✓ | ✓ |
-| Horizontal Bar | ✓ | ✓ | ✓ |
-| Pie/Doughnut | ✓ | ✓ | ✓ |
-| Polar Area | ✓ | ✓ | |
-| Radar | ✓ | | |
-| Scatter | ✓ | ✓ | ✓ |
-| Bubble | ✓ | | |
-| Gauges | | ✓ | |
-| Maps (Heat/Tree/etc.) | | ✓ | |
-
-### Popular Plugins
-
-There are many plugins that add additional functionality to Chart.js. Some particularly notable ones are listed here. In addition, many plugins can be found on the [Chart.js GitHub organization](https://github.com/chartjs).
-
- - Chart.Zoom.js - Enable zooming and panning on charts
- - Chart.Annotation.js - Draw lines and boxes on chart area
- - Chart.BarFunnel.js - Adds a bar funnel chart type
- - Chart.Deferred.js - Defer initial chart update until chart scrolls into viewport
- - Chart.Smith.js - Adds a smith chart type
- - Chart.LinearGauge.js - Adds a linear gauge chart type
-
-### Popular Extensions
-
-There are many extensions which are available for use with popular frameworks. Some particularly notable ones are listed here.
-
-#### Angular
- - angular-chart.js
- - tc-angular-chartjs
- - angular-chartjs
- - Angular Chart-js Directive
-
-#### React
- - react-chartjs2
- - react-chartjs-2
-
-#### Django
- - Django Chartjs
-
-#### Ruby on Rails
- - chartjs-ror
-
-#### Laravel
- - laravel-chartjs
diff --git a/contao/assets/chartjs/docs/README.md b/contao/assets/chartjs/docs/README.md
new file mode 100644
index 0000000..aa58722
--- /dev/null
+++ b/contao/assets/chartjs/docs/README.md
@@ -0,0 +1,65 @@
+# Chart.js
+
+[](https://chart-js-automation.herokuapp.com/)
+
+## Installation
+
+You can download the latest version of Chart.js from the [GitHub releases](https://github.com/chartjs/Chart.js/releases/latest) or use a [Chart.js CDN](https://cdnjs.com/libraries/Chart.js). Detailed installation instructions can be found on the [installation](./getting-started/installation.md) page.
+
+## Creating a Chart
+
+It's easy to get started with Chart.js. All that's required is the script included in your page along with a single `` node to render the chart.
+
+In this example, we create a bar chart for a single dataset and render that in our page. You can see all the ways to use Chart.js in the [usage documentation](./getting-started/usage.md)
+```html
+
+
+```
+
+## Contributing
+
+Before submitting an issue or a pull request to the project, please take a moment to look over the [contributing guidelines](https://github.com/chartjs/Chart.js/blob/master/docs/developers/contributing.md) first.
+
+For support using Chart.js, please post questions with the [`chartjs` tag on Stack Overflow](http://stackoverflow.com/questions/tagged/chartjs).
+
+## License
+
+Chart.js is available under the [MIT license](http://opensource.org/licenses/MIT).
diff --git a/contao/assets/chartjs/docs/SUMMARY.md b/contao/assets/chartjs/docs/SUMMARY.md
new file mode 100644
index 0000000..041be70
--- /dev/null
+++ b/contao/assets/chartjs/docs/SUMMARY.md
@@ -0,0 +1,52 @@
+# Summary
+
+* [Chart.js](README.md)
+* [Getting Started](getting-started/README.md)
+ * [Installation](getting-started/installation.md)
+ * [Integration](getting-started/integration.md)
+ * [Usage](getting-started/usage.md)
+* [General](general/README.md)
+ * [Responsive](general/responsive.md)
+ * [Interactions](general/interactions/README.md)
+ * [Events](general/interactions/events.md)
+ * [Modes](general/interactions/modes.md)
+ * [Colors](general/colors.md)
+ * [Fonts](general/fonts.md)
+* [Configuration](configuration/README.md)
+ * [Animations](configuration/animations.md)
+ * [Layout](configuration/layout.md)
+ * [Legend](configuration/legend.md)
+ * [Title](configuration/title.md)
+ * [Tooltip](configuration/tooltip.md)
+ * [Elements](configuration/elements.md)
+* [Charts](charts/README.md)
+ * [Line](charts/line.md)
+ * [Bar](charts/bar.md)
+ * [Radar](charts/radar.md)
+ * [Doughnut & Pie](charts/doughnut.md)
+ * [Polar Area](charts/polar.md)
+ * [Bubble](charts/bubble.md)
+ * [Scatter](charts/scatter.md)
+ * [Area](charts/area.md)
+ * [Mixed](charts/mixed.md)
+* [Axes](axes/README.md)
+ * [Cartesian](axes/cartesian/README.md)
+ * [Category](axes/cartesian/category.md)
+ * [Linear](axes/cartesian/linear.md)
+ * [Logarithmic](axes/cartesian/logarithmic.md)
+ * [Time](axes/cartesian/time.md)
+ * [Radial](axes/radial/README.md)
+ * [Linear](axes/radial/linear.md)
+ * [Labelling](axes/labelling.md)
+ * [Styling](axes/styling.md)
+* [Developers](developers/README.md)
+ * [Chart.js API](developers/api.md)
+ * [Updating Charts](developers/updates.md)
+ * [Plugins](developers/plugins.md)
+ * [New Charts](developers/charts.md)
+ * [New Axes](developers/axes.md)
+ * [Contributing](developers/contributing.md)
+* [Additional Notes](notes/README.md)
+ * [Comparison Table](notes/comparison.md)
+ * [Popular Extensions](notes/extensions.md)
+ * [License](notes/license.md)
diff --git a/contao/assets/chartjs/docs/axes/README.md b/contao/assets/chartjs/docs/axes/README.md
new file mode 100644
index 0000000..b7de691
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/README.md
@@ -0,0 +1,58 @@
+# Axes
+
+Axes are an integral part of a chart. They are used to determine how data maps to a pixel value on the chart. In a cartesian chart, there is 1 or more X axis and 1 or more Y axis to map points onto the 2 dimensional canvas. These axes are know as ['cartesian axes'](./cartesian/README.md#cartesian-axes).
+
+In a radial chart, such as a radar chart or a polar area chart, there is a single axis that maps points in the angular and radial directions. These are known as ['radial axes'](./radial/README.md#radial-axes).
+
+Scales in Chart.js >V2.0 are significantly more powerful, but also different than those of v1.0.
+* Multiple X & Y axes are supported.
+* A built-in label auto-skip feature detects would-be overlapping ticks and labels and removes every nth label to keep things displaying normally.
+* Scale titles are supported
+* New scale types can be extended without writing an entirely new chart type
+
+# Common Configuration
+
+The following properties are common to all axes provided by Chart.js
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `display` | `Boolean` | `true` | If set to `false` the axis is hidden from view. Overrides *gridLines.display*, *scaleLabel.display*, and *ticks.display*.
+| `callbacks` | `Object` | | Callback functions to hook into the axis lifecycle. [more...](#callbacks)
+| `weight` | `Number` | `0` | The weight used to sort the axis. Higher weights are further away from the chart area.
+
+## Callbacks
+There are a number of config callbacks that can be used to change parameters in the scale at different points in the update process.
+
+| Name | Arguments | Description
+| ---- | --------- | -----------
+| `beforeUpdate` | `axis` | Callback called before the update process starts.
+| `beforeSetDimensions` | `axis` | Callback that runs before dimensions are set.
+| `afterSetDimensions` | `axis` | Callback that runs after dimensions are set.
+| `beforeDataLimits` | `axis` | Callback that runs before data limits are determined.
+| `afterDataLimits` | `axis` | Callback that runs after data limits are determined.
+| `beforeBuildTicks` | `axis` | Callback that runs before ticks are created.
+| `afterBuildTicks` | `axis` | Callback that runs after ticks are created. Useful for filtering ticks.
+| `beforeTickToLabelConversion` | `axis` | Callback that runs before ticks are converted into strings.
+| `afterTickToLabelConversion` | `axis` | Callback that runs after ticks are converted into strings.
+| `beforeCalculateTickRotation` | `axis` | Callback that runs before tick rotation is determined.
+| `afterCalculateTickRotation` | `axis` | Callback that runs after tick rotation is determined.
+| `beforeFit` | `axis` | Callback that runs before the scale fits to the canvas.
+| `afterFit` | `axis` | Callback that runs after the scale fits to the canvas.
+| `afterUpdate` | `axis` | Callback that runs at the end of the update process.
+
+## Updating Axis Defaults
+
+The default configuration for a scale can be easily changed using the scale service. All you need to do is to pass in a partial configuration that will be merged with the current scale default configuration to form the new default.
+
+For example, to set the minimum value of 0 for all linear scales, you would do the following. Any linear scales created after this time would now have a minimum of 0.
+
+```javascript
+Chart.scaleService.updateScaleDefaults('linear', {
+ ticks: {
+ min: 0
+ }
+});
+```
+
+## Creating New Axes
+To create a new axis, see the [developer docs](../developers/axes.md).
diff --git a/contao/assets/chartjs/docs/axes/cartesian/README.md b/contao/assets/chartjs/docs/axes/cartesian/README.md
new file mode 100644
index 0000000..c545716
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/cartesian/README.md
@@ -0,0 +1,104 @@
+# Cartesian Axes
+
+Axes that follow a cartesian grid are known as 'Cartesian Axes'. Cartesian axes are used for line, bar, and bubble charts. Four cartesian axes are included in Chart.js by default.
+
+* [linear](./linear.md#linear-cartesian-axis)
+* [logarithmic](./logarithmic.md#logarithmic-cartesian-axis)
+* [category](./category.md#category-cartesian-axis)
+* [time](./time.md#time-cartesian-axis)
+
+# Common Configuration
+
+All of the included cartesian axes support a number of common options.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `type` | `String` | | Type of scale being employed. Custom scales can be created and registered with a string key. This allows changing the type of an axis for a chart.
+| `position` | `String` | | Position of the axis in the chart. Possible values are: `'top'`, `'left'`, `'bottom'`, `'right'`
+| `id` | `String` | | The ID is used to link datasets and scale axes together. [more...](#axis-id)
+| `gridLines` | `Object` | | Grid line configuration. [more...](../styling.md#grid-line-configuration)
+| `scaleLabel` | `Object` | | Scale title configuration. [more...](../labelling.md#scale-title-configuration)
+| `ticks` | `Object` | | Tick configuration. [more...](#tick-configuration)
+
+## Tick Configuration
+The following options are common to all cartesian axes but do not apply to other axes.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `autoSkip` | `Boolean` | `true` | If true, automatically calculates how many labels that can be shown and hides labels accordingly. Turn it off to show all labels no matter what
+| `autoSkipPadding` | `Number` | `0` | Padding between the ticks on the horizontal axis when `autoSkip` is enabled. *Note: Only applicable to horizontal scales.*
+| `labelOffset` | `Number` | `0` | Distance in pixels to offset the label from the centre point of the tick (in the y direction for the x axis, and the x direction for the y axis). *Note: this can cause labels at the edges to be cropped by the edge of the canvas*
+| `maxRotation` | `Number` | `90` | Maximum rotation for tick labels when rotating to condense labels. Note: Rotation doesn't occur until necessary. *Note: Only applicable to horizontal scales.*
+| `minRotation` | `Number` | `0` | Minimum rotation for tick labels. *Note: Only applicable to horizontal scales.*
+| `mirror` | `Boolean` | `false` | Flips tick labels around axis, displaying the labels inside the chart instead of outside. *Note: Only applicable to vertical scales.*
+| `padding` | `Number` | `10` | Padding between the tick label and the axis. *Note: Only applicable to horizontal scales.*
+
+## Axis ID
+The properties `dataset.xAxisID` or `dataset.yAxisID` have to match the scale properties `scales.xAxes.id` or `scales.yAxes.id`. This is especially needed if multi-axes charts are used.
+
+```javascript
+var myChart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ datasets: [{
+ // This dataset appears on the first axis
+ yAxisID: 'first-y-axis'
+ }, {
+ // This dataset appears on the second axis
+ yAxisID: 'second-y-axis'
+ }]
+ },
+ options: {
+ scales: {
+ yAxes: [{
+ id: 'first-y-axis',
+ type: 'linear'
+ }, {
+ id: 'second-y-axis',
+ type: 'linear'
+ }]
+ }
+ }
+});
+```
+
+# Creating Multiple Axes
+
+With cartesian axes, it is possible to create multiple X and Y axes. To do so, you can add multiple configuration objects to the `xAxes` and `yAxes` properties. When adding new axes, it is important to ensure that you specify the type of the new axes as default types are **not** used in this case.
+
+In the example below, we are creating two Y axes. We then use the `yAxisID` property to map the datasets to their correct axes.
+
+```javascript
+var myChart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ datasets: [{
+ data: [20, 50, 100, 75, 25, 0],
+ label: 'Left dataset'
+
+ // This binds the dataset to the left y axis
+ yAxisID: 'left-y-axis'
+ }, {
+ data: [0.1, 0.5, 1.0, 2.0, 1.5, 0]
+ label: 'Right dataset'
+
+ // This binds the dataset to the right y axis
+ yAxisID: 'right-y-axis',
+ }],
+ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
+ },
+ options: {
+ scales: {
+ yAxes: [{
+ id: 'left-y-axis',
+ type: 'linear',
+ position: 'left'
+ }, {
+ id: 'right-y-axis',
+ type: 'linear',
+ position: 'right'
+ }]
+ }
+ }
+});
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/axes/cartesian/category.md b/contao/assets/chartjs/docs/axes/cartesian/category.md
new file mode 100644
index 0000000..41bfd74
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/cartesian/category.md
@@ -0,0 +1,36 @@
+# Category Cartesian Axis
+
+The category scale will be familiar to those who have used v1.0. Labels are drawn from one of the label arrays included in the chart data. If only `data.labels` is defined, this will be used. If `data.xLabels` is defined and the axis is horizontal, this will be used. Similarly, if `data.yLabels` is defined and the axis is vertical, this property will be used. Using both `xLabels` and `yLabels` together can create a chart that uses strings for both the X and Y axes.
+
+## Tick Configuration Options
+
+The category scale provides the following options for configuring tick marks. They are nested in the `ticks` sub object. These options extend the [common tick configuration](README.md#tick-configuration).
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `min` | `String` | | The minimum item to display. [more...](#min-max-configuration)
+| `max` | `String` | | The maximum item to display. [more...](#min-max-configuration)
+
+## Min Max Configuration
+For both the `min` and `max` properties, the value must be in the `labels` array. In the example below, the x axis would only display "March" through "June".
+
+```javascript
+let chart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ datasets: [{
+ data: [10, 20, 30, 40, 50, 60]
+ }],
+ labels: ['January', 'February', 'March', 'April', 'May', 'June'],
+ },
+ options: {
+ scales: {
+ xAxes: [{
+ ticks: {
+ min: 'March'
+ }
+ }]
+ }
+ }
+});
+```
diff --git a/contao/assets/chartjs/docs/axes/cartesian/linear.md b/contao/assets/chartjs/docs/axes/cartesian/linear.md
new file mode 100644
index 0000000..00f7ace
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/cartesian/linear.md
@@ -0,0 +1,74 @@
+# Linear Cartesian Axis
+
+The linear scale is use to chart numerical data. It can be placed on either the x or y axis. The scatter chart type automatically configures a line chart to use one of these scales for the x axis. As the name suggests, linear interpolation is used to determine where a value lies on the axis.
+
+## Tick Configuration Options
+
+The following options are provided by the linear scale. They are all located in the `ticks` sub options. These options extend the [common tick configuration](README.md#tick-configuration).
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `beginAtZero` | `Boolean` | | if true, scale will include 0 if it is not already included.
+| `min` | `Number` | | User defined minimum number for the scale, overrides minimum value from data. [more...](#axis-range-settings)
+| `max` | `Number` | | User defined maximum number for the scale, overrides maximum value from data. [more...](#axis-range-settings)
+| `maxTicksLimit` | `Number` | `11` | Maximum number of ticks and gridlines to show.
+| `stepSize` | `Number` | | User defined fixed step size for the scale. [more...](#step-size)
+| `suggestedMax` | `Number` | | Adjustment used when calculating the maximum data value. [more...](#axis-range-settings)
+| `suggestedMin` | `Number` | | Adjustment used when calculating the minimum data value. [more...](#axis-range-settings)
+
+## Axis Range Settings
+
+Given the number of axis range settings, it is important to understand how they all interact with each other.
+
+The `suggestedMax` and `suggestedMin` settings only change the data values that are used to scale the axis. These are useful for extending the range of the axis while maintaing the auto fit behaviour.
+
+```javascript
+let minDataValue = Math.min(mostNegativeValue, options.ticks.suggestedMin);
+let maxDataValue = Math.max(mostPositiveValue, options.ticks.suggestedMax);
+```
+
+In this example, the largest positive value is 50, but the data maximum is expanded out to 100. However, because the lowest data value is below the `suggestedMin` setting, it is ignored.
+
+```javascript
+let chart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ datasets: [{
+ label: 'First dataset',
+ data: [0, 20, 40, 50]
+ }],
+ labels: ['January', 'February', 'March', 'April']
+ },
+ options: {
+ scales: {
+ yAxes: [{
+ ticks: {
+ suggestedMin: 50
+ suggestedMax: 100
+ }
+ }]
+ }
+ }
+});
+```
+
+In contrast to the `suggested*` settings, the `min` and `max` settings set explicit ends to the axes. When these are set, some data points may not be visible.
+
+## Step Size
+ If set, the scale ticks will be enumerated by multiple of stepSize, having one tick per increment. If not set, the ticks are labeled automatically using the nice numbers algorithm.
+
+This example sets up a chart with a y axis that creates ticks at `0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5`.
+
+```javascript
+let options = {
+ scales: {
+ yAxes: [{
+ ticks: {
+ max: 5,
+ min: 0,
+ stepSize: 0.5
+ }
+ }]
+ }
+};
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/axes/cartesian/logarithmic.md b/contao/assets/chartjs/docs/axes/cartesian/logarithmic.md
new file mode 100644
index 0000000..207c550
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/cartesian/logarithmic.md
@@ -0,0 +1,12 @@
+# Logarithmic Cartesian Axis
+
+The logarithmic scale is use to chart numerical data. It can be placed on either the x or y axis. As the name suggests, logarithmic interpolation is used to determine where a value lies on the axis.
+
+## Tick Configuration Options
+
+The following options are provided by the logarithmic scale. They are all located in the `ticks` sub options. These options extend the [common tick configuration](README.md#tick-configuration).
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `min` | `Number` | | User defined minimum number for the scale, overrides minimum value from data.
+| `max` | `Number` | | User defined maximum number for the scale, overrides maximum value from data.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/axes/cartesian/time.md b/contao/assets/chartjs/docs/axes/cartesian/time.md
new file mode 100644
index 0000000..67830e9
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/cartesian/time.md
@@ -0,0 +1,97 @@
+# Time Cartesian Axis
+
+The time scale is used to display times and dates. When building its ticks, it will automatically calculate the most comfortable unit base on the size of the scale.
+
+## Configuration Options
+
+The following options are provided by the time scale. They are all located in the `time` sub options. These options extend the [common tick configuration](README.md#tick-configuration).
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `displayFormats` | `Object` | | Sets how different time units are displayed. [more...](#display-formats)
+| `isoWeekday` | `Boolean` | `false` | If true and the unit is set to 'week', iso weekdays will be used.
+| `max` | [Time](#date-formats) | | If defined, this will override the data maximum
+| `min` | [Time](#date-formats) | | If defined, this will override the data minimum
+| `parser` | `String` or `Function` | | Custom parser for dates. [more...](#parser)
+| `round` | `String` | `false` | If defined, dates will be rounded to the start of this unit. See [Time Units](#scales-time-units) below for the allowed units.
+| `tooltipFormat` | `String` | | The moment js format string to use for the tooltip.
+| `unit` | `String` | `false` | If defined, will force the unit to be a certain type. See [Time Units](#scales-time-units) section below for details.
+| `unitStepSize` | `Number` | `1` | The number of units between grid lines.
+| `minUnit` | `String` | `millisecond` | The minimum display format to be used for a time unit.
+
+## Date Formats
+
+When providing data for the time scale, Chart.js supports all of the formats that Moment.js accepts. See [Moment.js docs](http://momentjs.com/docs/#/parsing/) for details.
+
+## Time Units
+
+The following time measurements are supported. The names can be passed as strings to the `time.unit` config option to force a certain unit.
+
+* millisecond
+* second
+* minute
+* hour
+* day
+* week
+* month
+* quarter
+* year
+
+For example, to create a chart with a time scale that always displayed units per month, the following config could be used.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ scales: {
+ xAxes: [{
+ time: {
+ unit: 'month'
+ }
+ }]
+ }
+ }
+})
+```
+
+## Display Formats
+The following display formats are used to configure how different time units are formed into strings for the axis tick marks. See [moment.js](http://momentjs.com/docs/#/displaying/format/) for the allowable format strings.
+
+Name | Default
+--- | ---
+millisecond | 'SSS [ms]'
+second | 'h:mm:ss a'
+minute | 'h:mm:ss a'
+hour | 'MMM D, hA'
+day | 'll'
+week | 'll'
+month | 'MMM YYYY'
+quarter | '[Q]Q - YYYY'
+year | 'YYYY'
+
+For example, to set the display format for the 'quarter' unit to show the month and year, the following config would be passed to the chart constructor.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ scales: {
+ xAxes: [{
+ type: 'time',
+ time: {
+ displayFormats: {
+ quarter: 'MMM YYYY'
+ }
+ }
+ }]
+ }
+ }
+})
+```
+
+## Parser
+If this property is defined as a string, it is interpreted as a custom format to be used by moment to parse the date.
+
+If this is a function, it must return a moment.js object given the appropriate data value.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/axes/labelling.md b/contao/assets/chartjs/docs/axes/labelling.md
new file mode 100644
index 0000000..c0dda84
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/labelling.md
@@ -0,0 +1,42 @@
+# Labeling Axes
+
+When creating a chart, you want to tell the viewer what data they are viewing. To do this, you need to label the axis.
+
+## Scale Title Configuration
+
+The scale label configuration is nested under the scale configuration in the `scaleLabel` key. It defines options for the scale title. Note that this only applies to cartesian axes.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `display` | `Boolean` | `false` | If true, display the axis title.
+| `labelString` | `String` | `''` | The text for the title. (i.e. "# of People" or "Respone Choices").
+| `fontColor` | Color | `'#666'` | Font color for scale title.
+| `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the scale title, follows CSS font-family options.
+| `fontSize` | `Number` | `12` | Font size for scale title.
+| `fontStyle` | `String` | `'normal'` | Font style for the scale title, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
+
+## Creating Custom Tick Formats
+
+It is also common to want to change the tick marks to include information about the data type. For example, adding a dollar sign ('$'). To do this, you need to override the `ticks.callback` method in the axis configuration.
+In the following example, every label of the Y axis would be displayed with a dollar sign at the front..
+
+If the callback returns `null` or `undefined` the associated grid line will be hidden.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ scales: {
+ yAxes: [{
+ ticks: {
+ // Include a dollar sign in the ticks
+ callback: function(value, index, values) {
+ return '$' + value;
+ }
+ }
+ }]
+ }
+ }
+});
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/axes/radial/README.md b/contao/assets/chartjs/docs/axes/radial/README.md
new file mode 100644
index 0000000..64ebe82
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/radial/README.md
@@ -0,0 +1,5 @@
+# Radial Axes
+
+Radial axes are used specifically for the radar and polar area chart types. These axes overlay the chart area, rather than being positioned on one of the edges. One radial axis is included by default in Chart.js.
+
+* [linear](./linear.md#linear-radial-axis)
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/axes/radial/linear.md b/contao/assets/chartjs/docs/axes/radial/linear.md
new file mode 100644
index 0000000..f9811c6
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/radial/linear.md
@@ -0,0 +1,110 @@
+# Linear Radial Axis
+
+The linear scale is use to chart numerical data. As the name suggests, linear interpolation is used to determine where a value lies in relation the center of the axis.
+
+The following additional configuration options are provided by the radial linear scale.
+
+## Configuration Options
+
+The axis has configuration properties for ticks, angle lines (line that appear in a radar chart outward from the center), pointLabels (labels around the edge in a radar chart). The following sections define each of the properties in those sections.
+
+| Name | Type | Description
+| ---- | ---- | -----------
+| `angleLines` | `Object` | Angle line configuration. [more...](#angle-line-options)
+| `gridLines` | `Object` | Grid line configuration. [more...](../styling.md#grid-line-configuration)
+| `pointLabels` | `Object` | Point label configuration. [more...](#point-label-options)
+| `ticks` | `Object` | Tick configuration. [more...](#tick-options)
+
+## Tick Options
+The following options are provided by the linear scale. They are all located in the `ticks` sub options. The [common tick configuration](../styling.md#tick-configuration) options are supported by this axis.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `backdropColor` | Color | `'rgba(255, 255, 255, 0.75)'` | Color of label backdrops
+| `backdropPaddingX` | `Number` | `2` | Horizontal padding of label backdrop.
+| `backdropPaddingY` | `Number` | `2` | Vertical padding of label backdrop.
+| `beginAtZero` | `Boolean` | `false` | if true, scale will include 0 if it is not already included.
+| `min` | `Number` | | User defined minimum number for the scale, overrides minimum value from data. [more...](#axis-range-settings)
+| `max` | `Number` | | User defined maximum number for the scale, overrides maximum value from data. [more...](#axis-range-settings)
+| `maxTicksLimit` | `Number` | `11` | Maximum number of ticks and gridlines to show.
+| `stepSize` | `Number` | | User defined fixed step size for the scale. [more...](#step-size)
+| `suggestedMax` | `Number` | | Adjustment used when calculating the maximum data value. [more...](#axis-range-settings)
+| `suggestedMin` | `Number` | | Adjustment used when calculating the minimum data value. [more...](#axis-range-settings)
+| `showLabelBackdrop` | `Boolean` | `true` | If true, draw a background behind the tick labels
+
+## Axis Range Settings
+
+Given the number of axis range settings, it is important to understand how they all interact with each other.
+
+The `suggestedMax` and `suggestedMin` settings only change the data values that are used to scale the axis. These are useful for extending the range of the axis while maintaing the auto fit behaviour.
+
+```javascript
+let minDataValue = Math.min(mostNegativeValue, options.ticks.suggestedMin);
+let maxDataValue = Math.max(mostPositiveValue, options.ticks.suggestedMax);
+```
+
+In this example, the largest positive value is 50, but the data maximum is expanded out to 100. However, because the lowest data value is below the `suggestedMin` setting, it is ignored.
+
+```javascript
+let chart = new Chart(ctx, {
+ type: 'radar',
+ data: {
+ datasets: [{
+ label: 'First dataset',
+ data: [0, 20, 40, 50]
+ }],
+ labels: ['January', 'February', 'March', 'April']
+ },
+ options: {
+ scale: {
+ ticks: {
+ suggestedMin: 50
+ suggestedMax: 100
+ }
+ }
+ }
+});
+```
+
+In contrast to the `suggested*` settings, the `min` and `max` settings set explicit ends to the axes. When these are set, some data points may not be visible.
+
+## Step Size
+ If set, the scale ticks will be enumerated by multiple of stepSize, having one tick per increment. If not set, the ticks are labeled automatically using the nice numbers algorithm.
+
+This example sets up a chart with a y axis that creates ticks at `0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5`.
+
+```javascript
+let options = {
+ scales: {
+ yAxes: [{
+ ticks: {
+ max: 5,
+ min: 0,
+ stepSize: 0.5
+ }
+ }]
+ }
+};
+```
+
+## Angle Line Options
+
+The following options are used to configure angled lines that radiate from the center of the chart to the point labels. They can be found in the `angleLines` sub options. Note that these options only apply if `angleLines.display` is true.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `display` | `Boolean` | `true` | if true, angle lines are shown
+| `color` | Color | `rgba(0, 0, 0, 0.1)` | Color of angled lines
+| `lineWidth` | `Number` | `1` | Width of angled lines
+
+## Point Label Options
+
+The following options are used to configure the point labels that are shown on the perimeter of the scale. They can be found in the `pointLabels` sub options. Note that these options only apply if `pointLabels.display` is true.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `callback` | `Function` | | Callback function to transform data labels to point labels. The default implementation simply returns the current string.
+| `fontColor` | Color | `'#666'` | Font color for point labels.
+| `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family to use when rendering labels.
+| `fontSize` | `Number` | 10 | font size in pixels
+| `fontStyle` | `String` | `'normal'` | Font style to use when rendering point labels.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/axes/styling.md b/contao/assets/chartjs/docs/axes/styling.md
new file mode 100644
index 0000000..48a4d7d
--- /dev/null
+++ b/contao/assets/chartjs/docs/axes/styling.md
@@ -0,0 +1,37 @@
+# Styling
+
+There are a number of options to allow styling an axis. There are settings to control [grid lines](#grid-line-configuration) and [ticks](#tick-configuration).
+
+## Grid Line Configuration
+
+The grid line configuration is nested under the scale configuration in the `gridLines` key. It defines options for the grid lines that run perpendicular to the axis.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `display` | `Boolean` | `true` | If false, do not display grid lines for this axis.
+| `color` | Color or Color[] | `'rgba(0, 0, 0, 0.1)'` | The color of the grid lines. If specified as an array, the first color applies to the first grid line, the second to the second grid line and so on.
+| `borderDash` | `Number[]` | `[]` | Length and spacing of dashes on grid lines. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
+| `borderDashOffset` | `Number` | `0` | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
+| `lineWidth` | `Number or Number[]` | `1` | Stroke width of grid lines.
+| `drawBorder` | `Boolean` | `true` | If true, draw border at the edge between the axis and the chart area.
+| `drawOnChartArea` | `Boolean` | `true` | If true, draw lines on the chart area inside the axis lines. This is useful when there are multiple axes and you need to control which grid lines are drawn.
+| `drawTicks` | `Boolean` | `true` | If true, draw lines beside the ticks in the axis area beside the chart.
+| `tickMarkLength` | `Number` | `10` | Length in pixels that the grid lines will draw into the axis area.
+| `zeroLineWidth` | `Number` | `1` | Stroke width of the grid line for the first index (index 0).
+| `zeroLineColor` | Color | `'rgba(0, 0, 0, 0.25)'` | Stroke color of the grid line for the first index (index 0).
+| `zeroLineBorderDash` | `Number[]` | `[]` | Length and spacing of dashes of the grid line for the first index (index 0). See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
+| `zeroLineBorderDashOffset` | `Number` | `0` | Offset for line dashes of the grid line for the first index (index 0). See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
+| `offsetGridLines` | `Boolean` | `false` | If true, labels are shifted to be between grid lines. This is used in the bar chart and should not generally be used.
+
+## Tick Configuration
+The tick configuration is nested under the scale configuration in the `ticks` key. It defines options for the tick marks that are generated by the axis.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `callback` | `Function` | | Returns the string representation of the tick value as it should be displayed on the chart. See [callback](../axes/labelling.md#creating-custom-tick-formats).
+| `display` | `Boolean` | `true` | If true, show tick marks
+| `fontColor` | Color | `'#666'` | Font color for tick labels.
+| `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the tick labels, follows CSS font-family options.
+| `fontSize` | `Number` | `12` | Font size for the tick labels.
+| `fontStyle` | `String` | `'normal'` | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
+| `reverse` | `Boolean` | `false` | Reverses order of tick labels.
diff --git a/contao/assets/chartjs/docs/charts/README.md b/contao/assets/chartjs/docs/charts/README.md
new file mode 100644
index 0000000..26677b0
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/README.md
@@ -0,0 +1,13 @@
+# Charts
+
+Chart.js comes with built-in chart types:
+* [line](./line.md)
+* [bar](./bar.md)
+* [radar](./radar.md)
+* [polar area](./polar.md)
+* [doughnut and pie](./doughnut.md)
+* [bubble](./bubble.md)
+
+[Area charts](area.md) can be built from a line or radar chart using the dataset `fill` option.
+
+To create a new chart type, see the [developer notes](../developers/charts.md#new-charts)
diff --git a/contao/assets/chartjs/docs/charts/area.md b/contao/assets/chartjs/docs/charts/area.md
new file mode 100644
index 0000000..3389c87
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/area.md
@@ -0,0 +1,72 @@
+# Area Charts
+
+Both [line](line.md) and [radar](radar.md) charts support a `fill` option on the dataset object which can be used to create area between two datasets or a dataset and a boundary, i.e. the scale `origin`, `start` or `end` (see [filling modes](#filling-modes)).
+
+> **Note:** this feature is implemented by the [`filler` plugin](https://github.com/chartjs/Chart.js/blob/master/src/plugins/plugin.filler.js).
+
+## Filling modes
+
+| Mode | Type | Values |
+| :--- | :--- | :--- |
+| Absolute dataset index 1 | `Number` | `1`, `2`, `3`, ... |
+| Relative dataset index 1 | `String` | `'-1'`, `'-2'`, `'+1'`, ... |
+| Boundary 2 | `String` | `'start'`, `'end'`, `'origin'` |
+| Disabled 3 | `Boolean` | `false` |
+
+> 1 dataset filling modes have been introduced in version 2.6.0
+> 2 prior version 2.6.0, boundary values was `'zero'`, `'top'`, `'bottom'` (deprecated)
+> 3 for backward compatibility, `fill: true` (default) is equivalent to `fill: 'origin'`
+
+**Example**
+```javascript
+new Chart(ctx, {
+ data: {
+ datasets: [
+ {fill: 'origin'}, // 0: fill to 'origin'
+ {fill: '+2'}, // 1: fill to dataset 3
+ {fill: 1}, // 2: fill to dataset 1
+ {fill: false}, // 3: no fill
+ {fill: '-2'} // 4: fill to dataset 2
+ ]
+ }
+})
+```
+
+## Configuration
+| Option | Type | Default | Description |
+| :--- | :--- | :--- | :--- |
+| [`plugins.filler.propagate`](#propagate) | `Boolean` | `true` | Fill propagation when target is hidden
+
+### propagate
+Boolean (default: `true`)
+
+If `true`, the fill area will be recursively extended to the visible target defined by the `fill` value of hidden dataset targets:
+
+**Example**
+```javascript
+new Chart(ctx, {
+ data: {
+ datasets: [
+ {fill: 'origin'}, // 0: fill to 'origin'
+ {fill: '-1'}, // 1: fill to dataset 0
+ {fill: 1}, // 2: fill to dataset 1
+ {fill: false}, // 3: no fill
+ {fill: '-2'} // 4: fill to dataset 2
+ ]
+ },
+ options: {
+ plugins: {
+ filler: {
+ propagate: true
+ }
+ }
+ }
+})
+```
+
+`propagate: true`:
+- if dataset 2 is hidden, dataset 4 will fill to dataset 1
+- if dataset 2 and 1 are hidden, dataset 4 will fill to `'origin'`
+
+`propagate: false`:
+- if dataset 2 and/or 4 are hidden, dataset 4 will not be filled
diff --git a/contao/assets/chartjs/docs/charts/bar.md b/contao/assets/chartjs/docs/charts/bar.md
new file mode 100644
index 0000000..32cc32e
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/bar.md
@@ -0,0 +1,240 @@
+# Bar
+A bar chart provides a way of showing data values represented as vertical bars. It is sometimes used to show trend data, and the comparison of multiple data sets side by side.
+
+{% chartjs %}
+{
+ "type": "bar",
+ "data": {
+ "labels": [
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July"
+ ],
+ "datasets": [{
+ "label": "My First Dataset",
+ "data": [65, 59, 80, 81, 56, 55, 40],
+ "fill": false,
+ "backgroundColor": [
+ "rgba(255, 99, 132, 0.2)",
+ "rgba(255, 159, 64, 0.2)",
+ "rgba(255, 205, 86, 0.2)",
+ "rgba(75, 192, 192, 0.2)",
+ "rgba(54, 162, 235, 0.2)",
+ "rgba(153, 102, 255, 0.2)",
+ "rgba(201, 203, 207, 0.2)"
+ ],
+ "borderColor": [
+ "rgb(255, 99, 132)",
+ "rgb(255, 159, 64)",
+ "rgb(255, 205, 86)",
+ "rgb(75, 192, 192)",
+ "rgb(54, 162, 235)",
+ "rgb(153, 102, 255)",
+ "rgb(201, 203, 207)"
+ ],
+ "borderWidth": 1
+ }]
+ },
+ "options": {
+ "scales": {
+ "yAxes": [{
+ "ticks": {
+ "beginAtZero": true
+ }
+ }]
+ }
+ }
+}
+{% endchartjs %}
+
+## Example Usage
+```javascript
+var myBarChart = new Chart(ctx, {
+ type: 'bar',
+ data: data,
+ options: options
+});
+```
+
+## Dataset Properties
+The bar chart allows a number of properties to be specified for each dataset. These are used to set display properties for a specific dataset. For example, the colour of the bars is generally set this way.
+
+Some properties can be specified as an array. If these are set to an array value, the first value applies to the first bar, the second value to the second bar, and so on.
+
+| Name | Type | Description
+| ---- | ---- | -----------
+| `label` | `String` | The label for the dataset which appears in the legend and tooltips.
+| `xAxisID` | `String` | The ID of the x axis to plot this dataset on. If not specified, this defaults to the ID of the first found x axis
+| `yAxisID` | `String` | The ID of the y axis to plot this dataset on. If not specified, this defaults to the ID of the first found y axis.
+| `backgroundColor` | `Color/Color[]` | The fill color of the bar. See [Colors](../general/colors.md#colors)
+| `borderColor` | `Color/Color[]` | The color of the bar border. See [Colors](../general/colors.md#colors)
+| `borderWidth` | `Number/Number[]` | The stroke width of the bar in pixels.
+| `borderSkipped` | `String` | Which edge to skip drawing the border for. [more...](#borderSkipped)
+| `hoverBackgroundColor` | `Color/Color[]` | The fill colour of the bars when hovered.
+| `hoverBorderColor` | `Color/Color[]` | The stroke colour of the bars when hovered.
+| `hoverBorderWidth` | `Number/Number[]` | The stroke width of the bars when hovered.
+
+### borderSkipped
+This setting is used to avoid drawing the bar stroke at the base of the fill. In general, this does not need to be changed except when creating chart types that derive from a bar chart.
+
+Options are:
+* 'bottom'
+* 'left'
+* 'top'
+* 'right'
+
+## Configuration Options
+
+The bar chart defines the following configuration options. These options are merged with the global chart configuration options, `Chart.defaults.global`, to form the options passed to the chart.
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `barPercentage` | `Number` | `0.9` | Percent (0-1) of the available width each bar should be within the category percentage. 1.0 will take the whole category width and put the bars right next to each other. [more...](#bar-chart-barpercentage-vs-categorypercentage)
+| `categoryPercentage` | `Number` | `0.8` | Percent (0-1) of the available width (the space between the gridlines for small datasets) for each data-point to use for the bars. [more...](#bar-chart-barpercentage-vs-categorypercentage)
+| `barThickness` | `Number` | | Manually set width of each bar in pixels. If not set, the bars are sized automatically using `barPercentage` and `categoryPercentage`;
+| `maxBarThickness` | `Number` | | Set this to ensure that the automatically sized bars are not sized thicker than this. Only works if barThickness is not set (automatic sizing is enabled).
+| `gridLines.offsetGridLines` | `Boolean` | `true` | If true, the bars for a particular data point fall between the grid lines. If false, the grid line will go right down the middle of the bars. [more...](#offsetGridLines)
+
+### offsetGridLines
+If true, the bars for a particular data point fall between the grid lines. If false, the grid line will go right down the middle of the bars. It is unlikely that this will ever need to be changed in practice. It exists more as a way to reuse the axis code by configuring the existing axis slightly differently.
+
+This setting applies to the axis configuration for a bar chart. If axes are added to the chart, this setting will need to be set for each new axis.
+
+```javascript
+options = {
+ scales: {
+ xAxes: [{
+ gridLines: {
+ offsetGridLines: true
+ }
+ }]
+ }
+}
+```
+
+## Default Options
+
+It is common to want to apply a configuration setting to all created bar charts. The global bar chart settings are stored in `Chart.defaults.bar`. Changing the global options only affects charts created after the change. Existing charts are not changed.
+
+## barPercentage vs categoryPercentage
+
+The following shows the relationship between the bar percentage option and the category percentage option.
+
+```text
+// categoryPercentage: 1.0
+// barPercentage: 1.0
+Bar: | 1.0 | 1.0 |
+Category: | 1.0 |
+Sample: |===========|
+
+// categoryPercentage: 1.0
+// barPercentage: 0.5
+Bar: |.5| |.5|
+Category: | 1.0 |
+Sample: |==============|
+
+// categoryPercentage: 0.5
+// barPercentage: 1.0
+Bar: |1.||1.|
+Category: | .5 |
+Sample: |==============|
+```
+
+## Data Structure
+
+The `data` property of a dataset for a bar chart is specified as a an array of numbers. Each point in the data array corresponds to the label at the same index on the x axis.
+
+```javascript
+data: [20, 10]
+```
+
+# Stacked Bar Chart
+
+Bar charts can be configured into stacked bar charts by changing the settings on the X and Y axes to enable stacking. Stacked bar charts can be used to show how one data series is made up of a number of smaller pieces.
+
+```javascript
+var stackedBar = new Chart(ctx, {
+ type: 'bar',
+ data: data,
+ options: {
+ scales: {
+ xAxes: [{
+ stacked: true
+ }],
+ yAxes: [{
+ stacked: true
+ }]
+ }
+ }
+});
+```
+
+## Dataset Properties
+
+The following dataset properties are specific to stacked bar charts.
+
+| Name | Type | Description
+| ---- | ---- | -----------
+| `stack` | `String` | The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack)
+
+# Horizontal Bar Chart
+A horizontal bar chart is a variation on a vertical bar chart. It is sometimes used to show trend data, and the comparison of multiple data sets side by side.
+{% chartjs %}
+{
+ "type": "horizontalBar",
+ "data": {
+ "labels": ["January", "February", "March", "April", "May", "June", "July"],
+ "datasets": [{
+ "label": "My First Dataset",
+ "data": [65, 59, 80, 81, 56, 55, 40],
+ "fill": false,
+ "backgroundColor": [
+ "rgba(255, 99, 132, 0.2)",
+ "rgba(255, 159, 64, 0.2)",
+ "rgba(255, 205, 86, 0.2)",
+ "rgba(75, 192, 192, 0.2)",
+ "rgba(54, 162, 235, 0.2)",
+ "rgba(153, 102, 255, 0.2)",
+ "rgba(201, 203, 207, 0.2)"
+ ],
+ "borderColor": [
+ "rgb(255, 99, 132)",
+ "rgb(255, 159, 64)",
+ "rgb(255, 205, 86)",
+ "rgb(75, 192, 192)",
+ "rgb(54, 162, 235)",
+ "rgb(153, 102, 255)",
+ "rgb(201, 203, 207)"
+ ],
+ "borderWidth": 1
+ }]
+ },
+ "options": {
+ "scales": {
+ "xAxes": [{
+ "ticks": {
+ "beginAtZero": true
+ }
+ }]
+ }
+ }
+}
+{% endchartjs %}
+
+## Example
+```javascript
+var myBarChart = new Chart(ctx, {
+ type: 'horizontalBar',
+ data: data,
+ options: options
+});
+```
+
+## Config Options
+The configuration options for the horizontal bar chart are the same as for the [bar chart](../bar/config-options.md#config-options). However, any options specified on the x axis in a bar chart, are applied to the y axis in a horizontal bar chart.
+
+The default horizontal bar configuration is specified in `Chart.defaults.horizontalBar`.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/charts/bubble.md b/contao/assets/chartjs/docs/charts/bubble.md
new file mode 100644
index 0000000..d36f7ee
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/bubble.md
@@ -0,0 +1,81 @@
+# Bubble Chart
+
+A bubble chart is used to display three dimensions of data at the same time. The location of the bubble is determined by the first two dimensions and the corresponding horizontal and vertical axes. The third dimension is represented by the size of the individual bubbles.
+
+{% chartjs %}
+{
+ "type": "bubble",
+ "data": {
+ "datasets": [{
+ "label": "First Dataset",
+ "data": [{
+ "x": 20,
+ "y": 30,
+ "r": 15
+ }, {
+ "x": 40,
+ "y": 10,
+ "r": 10
+ }],
+ "backgroundColor": "rgb(255, 99, 132)"
+ }]
+ },
+}
+{% endchartjs %}
+
+## Example Usage
+
+```javascript
+// For a bubble chart
+var myBubbleChart = new Chart(ctx,{
+ type: 'bubble',
+ data: data,
+ options: options
+});
+```
+
+## Dataset Properties
+
+The bubble chart allows a number of properties to be specified for each dataset. These are used to set display properties for a specific dataset. For example, the colour of the bubbles is generally set this way.
+
+All properties, except `label` can be specified as an array. If these are set to an array value, the first value applies to the first bubble in the dataset, the second value to the second bubble, and so on.
+
+| Name | Type | Description
+| ---- | ---- | -----------
+| `label` | `String` | The label for the dataset which appears in the legend and tooltips.
+| `backgroundColor` | `Color/Color[]` | The fill color for bubbles.
+| `borderColor` | `Color/Color[]` | The border color for bubbles.
+| `borderWidth` | `Number/Number[]` | The width of the point bubbles in pixels.
+| `hoverBackgroundColor` | `Color/Color[]` | Bubble background color when hovered.
+| `hoverBorderColor` | `Color/Color[]` | Bubble border color when hovered.
+| `hoverBorderWidth` | `Number/Number[]` | Border width of point when hovered.
+| `hoverRadius` | `Number/Number[]` | Additional radius to add to data radius on hover.
+
+## Config Options
+
+The bubble chart has no unique configuration options. To configure options common to all of the bubbles, the [point element options](../configuration/elements/point.md#point-configuration) are used.
+
+## Default Options
+
+We can also change the default values for the Bubble chart type. Doing so will give all bubble charts created after this point the new defaults. The default configuration for the bubble chart can be accessed at `Chart.defaults.bubble`.
+
+## Data Structure
+
+For a bubble chart, datasets need to contain an array of data points. Each point must implement the [bubble data object](#bubble-data-object) interface.
+
+### Bubble Data Object
+
+Data for the bubble chart is passed in the form of an object. The object must implement the following interface. It is important to note that the radius property, `r` is **not** scaled by the chart. It is the raw radius in pixels of the bubble that is drawn on the canvas.
+
+```javascript
+{
+ // X Value
+ x: ,
+
+ // Y Value
+ y: ,
+
+ // Radius of bubble. This is not scaled.
+ r:
+}
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/charts/doughnut.md b/contao/assets/chartjs/docs/charts/doughnut.md
new file mode 100644
index 0000000..35a7dbb
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/doughnut.md
@@ -0,0 +1,101 @@
+# Doughnut and Pie
+Pie and doughnut charts are probably the most commonly used charts. They are divided into segments, the arc of each segment shows the proportional value of each piece of data.
+
+They are excellent at showing the relational proportions between data.
+
+Pie and doughnut charts are effectively the same class in Chart.js, but have one different default value - their `cutoutPercentage`. This equates what percentage of the inner should be cut out. This defaults to `0` for pie charts, and `50` for doughnuts.
+
+They are also registered under two aliases in the `Chart` core. Other than their different default value, and different alias, they are exactly the same.
+
+{% chartjs %}
+{
+ "type": "doughnut",
+ "data": {
+ "labels": [
+ "Red",
+ "Blue",
+ "Yellow",
+ ],
+ "datasets": [{
+ "label": "My First Dataset",
+ "data": [300, 50, 100],
+ "backgroundColor": [
+ "rgb(255, 99, 132)",
+ "rgb(54, 162, 235)",
+ "rgb(255, 205, 86)",
+ ]
+ }]
+ },
+}
+{% endchartjs %}
+
+## Example Usage
+
+```javascript
+// For a pie chart
+var myPieChart = new Chart(ctx,{
+ type: 'pie',
+ data: data,
+ options: options
+});
+```
+
+```javascript
+// And for a doughnut chart
+var myDoughnutChart = new Chart(ctx, {
+ type: 'doughnut',
+ data: data,
+ options: options
+});
+```
+
+## Dataset Properties
+
+The doughnut/pie chart allows a number of properties to be specified for each dataset. These are used to set display properties for a specific dataset. For example, the colour of a the dataset's arc are generally set this way.
+
+| Name | Type | Description
+| ---- | ---- | -----------
+| `label` | `String` | The label for the dataset which appears in the legend and tooltips.
+| `backgroundColor` | `Color[]` | The fill color of the arcs in the dataset. See [Colors](../general/colors.md#colors)
+| `borderColor` | `Color[]` | The border color of the arcs in the dataset. See [Colors](../general/colors.md#colors)
+| `borderWidth` | `Number[]` | The border width of the arcs in the dataset.
+| `hoverBackgroundColor` | `Color[]` | The fill colour of the arcs when hovered.
+| `hoverBorderColor` | `Color[]` | The stroke colour of the arcs when hovered.
+| `hoverBorderWidth` | `Number[]` | The stroke width of the arcs when hovered.
+
+## Config Options
+
+These are the customisation options specific to Pie & Doughnut charts. These options are merged with the global chart configuration options, and form the options of the chart.
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `cutoutPercentage` | `Number` | `50` - for doughnut, `0` - for pie | The percentage of the chart that is cut out of the middle.
+| `rotation` | `Number` | `-0.5 * Math.PI` | Starting angle to draw arcs from.
+| `circumference` | `Number` | `2 * Math.PI` | Sweep to allow arcs to cover
+| `animation.animateRotate` | `Boolean` | `true` | If true, the chart will animate in with a rotation animation. This property is in the `options.animation` object.
+| `animation.animateScale` | `Boolean` | `false` | If true, will animate scaling the chart from the center outwards.
+
+## Default Options
+
+We can also change these default values for each Doughnut type that is created, this object is available at `Chart.defaults.doughnut`. Pie charts also have a clone of these defaults available to change at `Chart.defaults.pie`, with the only difference being `cutoutPercentage` being set to 0.
+
+## Data Structure
+
+For a pie chart, datasets need to contain an array of data points. The data points should be a number, Chart.js will total all of the numbers and calculate the relative proportion of each.
+
+You also need to specify an array of labels so that tooltips appear correctly
+
+```javascript
+data = {
+ datasets: [{
+ data: [10, 20, 30]
+ }],
+
+ // These labels appear in the legend and in the tooltips when hovering different arcs
+ labels: [
+ 'Red',
+ 'Yellow',
+ 'Blue'
+ ]
+};
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/charts/line.md b/contao/assets/chartjs/docs/charts/line.md
new file mode 100644
index 0000000..ba7911f
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/line.md
@@ -0,0 +1,241 @@
+# Line
+A line chart is a way of plotting data points on a line. Often, it is used to show trend data, or the comparison of two data sets.
+
+{% chartjs %}
+{
+ "type": "line",
+ "data": {
+ "labels": [
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July"
+ ],
+ "datasets": [{
+ "label": "My First Dataset",
+ "data": [65, 59, 80, 81, 56, 55, 40],
+ "fill": false,
+ "borderColor": "rgb(75, 192, 192)",
+ "lineTension": 0.1
+ }]
+ },
+ "options": {
+
+ }
+}
+{% endchartjs %}
+
+## Example Usage
+```javascript
+var myLineChart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: options
+});
+```
+
+## Dataset Properties
+
+The line chart allows a number of properties to be specified for each dataset. These are used to set display properties for a specific dataset. For example, the colour of a line is generally set this way.
+
+All point* properties can be specified as an array. If these are set to an array value, the first value applies to the first point, the second value to the second point, and so on.
+
+| Name | Type | Description
+| ---- | ---- | -----------
+| `label` | `String` | The label for the dataset which appears in the legend and tooltips.
+| `xAxisID` | `String` | The ID of the x axis to plot this dataset on. If not specified, this defaults to the ID of the first found x axis
+| `yAxisID` | `String` | The ID of the y axis to plot this dataset on. If not specified, this defaults to the ID of the first found y axis.
+| `backgroundColor` | `Color/Color[]` | The fill color under the line. See [Colors](../general/colors.md#colors)
+| `borderColor` | `Color/Color[]` | The color of the line. See [Colors](../general/colors.md#colors)
+| `borderWidth` | `Number/Number[]` | The width of the line in pixels.
+| `borderDash` | `Number[]` | Length and spacing of dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
+| `borderDashOffset` | `Number` | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
+| `borderCapStyle` | `String` | Cap style of the line. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap)
+| `borderJoinStyle` | `String` | Line joint style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
+| `cubicInterpolationMode` | `String` | Algorithm used to interpolate a smooth curve from the discrete data points. [more...](#cubicInterpolationMode)
+| `fill` | `Boolean/String` | How to fill the area under the line. See [area charts](area.md)
+| `lineTension` | `Number` | Bezier curve tension of the line. Set to 0 to draw straightlines. This option is ignored if monotone cubic interpolation is used.
+| `pointBackgroundColor` | `Color/Color[]` | The fill color for points.
+| `pointBorderColor` | `Color/Color[]` | The border color for points.
+| `pointBorderWidth` | `Number/Number[]` | The width of the point border in pixels.
+| `pointRadius` | `Number/Number[]` | The radius of the point shape. If set to 0, the point is not rendered.
+| `pointStyle` | `String/String[]/Image/Image[]` | Style of the point. [more...](#pointStyle)
+| `pointHitRadius` | `Number/Number[]` | The pixel size of the non-displayed point that reacts to mouse events.
+| `pointHoverBackgroundColor` | `Color/Color[]` | Point background color when hovered.
+| `pointHoverBorderColor` | `Color/Color[]` | Point border color when hovered.
+| `pointHoverBorderWidth` | `Number/Number[]` | Border width of point when hovered.
+| `pointHoverRadius` | `Number/Number[]` | The radius of the point when hovered.
+| `showLine` | `Boolean` | If false, the line is not drawn for this dataset.
+| `spanGaps` | `Boolean` | If true, lines will be drawn between points with no or null data. If false, points with `NaN` data will create a break in the line
+| `steppedLine` | `Boolean/String` | If the line is shown as a stepped line. [more...](#stepped-line)
+
+### cubicInterpolationMode
+The following interpolation modes are supported:
+* 'default'
+* 'monotone'.
+
+The 'default' algorithm uses a custom weighted cubic interpolation, which produces pleasant curves for all types of datasets.
+
+The 'monotone' algorithm is more suited to `y = f(x)` datasets : it preserves monotonicity (or piecewise monotonicity) of the dataset being interpolated, and ensures local extremums (if any) stay at input data points.
+
+If left untouched (`undefined`), the global `options.elements.line.cubicInterpolationMode` property is used.
+
+### pointStyle
+The style of point. Options are:
+* 'circle'
+* 'cross'
+* 'crossRot'
+* 'dash'.
+* 'line'
+* 'rect'
+* 'rectRounded'
+* 'rectRot'
+* 'star'
+* 'triangle'
+
+If the option is an image, that image is drawn on the canvas using [drawImage](https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/drawImage).
+
+### Stepped Line
+The following values are supported for `steppedLine`:
+* `false`: No Step Interpolation (default)
+* `true`: Step-before Interpolation (eq. 'before')
+* `'before'`: Step-before Interpolation
+* `'after'`: Step-after Interpolation
+
+If the `steppedLine` value is set to anything other than false, `lineTension` will be ignored.
+
+## Configuration Options
+
+The line chart defines the following configuration options. These options are merged with the global chart configuration options, `Chart.defaults.global`, to form the options passed to the chart.
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `showLines` | `Boolean` | `true` | If false, the lines between points are not drawn.
+| `spanGaps` | `Boolean` | `false` | If false, NaN data causes a break in the line.
+
+## Default Options
+
+It is common to want to apply a configuration setting to all created line charts. The global line chart settings are stored in `Chart.defaults.line`. Changing the global options only affects charts created after the change. Existing charts are not changed.
+
+For example, to configure all line charts with `spanGaps = true` you would do:
+```javascript
+Chart.defaults.line.spanGaps = true;
+```
+
+## Data Structure
+
+The `data` property of a dataset for a line chart can be passed in two formats.
+
+### Number[]
+```javascript
+data: [20, 10]
+```
+
+When the `data` array is an array of numbers, the x axis is generally a [category](../axes/cartesian/category.md#Category Axis). The points are placed onto the axis using their position in the array. When a line chart is created with a category axis, the `labels` property of the data object must be specified.
+
+### Point[]
+
+```javascript
+data: [{
+ x: 10,
+ y: 20
+ }, {
+ x: 15,
+ y: 10
+ }]
+```
+
+This alternate is used for sparse datasets, such as those in [scatter charts](./scatter.md#scatter-chart). Each data point is specified using an object containing `x` and `y` properties.
+
+# Stacked Area Chart
+
+Line charts can be configured into stacked area charts by changing the settings on the y axis to enable stacking. Stacked area charts can be used to show how one data trend is made up of a number of smaller pieces.
+
+```javascript
+var stackedLine = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ scales: {
+ yAxes: [{
+ stacked: true
+ }]
+ }
+ }
+});
+```
+
+# High Performance Line Charts
+
+When charting a lot of data, the chart render time may start to get quite large. In that case, the following strategies can be used to improve performance.
+
+## Data Decimation
+
+Decimating your data will achieve the best results. When there is a lot of data to display on the graph, it doesn't make sense to show tens of thousands of data points on a graph that is only a few hundred pixels wide.
+
+There are many approaches to data decimation and selection of an algorithm will depend on your data and the results you want to achieve. For instance, [min/max](http://digital.ni.com/public.nsf/allkb/F694FFEEA0ACF282862576020075F784) decimation will preserve peaks in your data but could require up to 4 points for each pixel. This type of decimation would work well for a very noisy signal where you need to see data peaks.
+
+## Disable Bezier Curves
+
+If you are drawing lines on your chart, disabling bezier curves will improve render times since drawing a straight line is more performant than a bezier curve.
+
+To disable bezier curves for an entire chart:
+
+```javascript
+new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ elements: {
+ line: {
+ tension: 0, // disables bezier curves
+ }
+ }
+ }
+});
+```
+
+## Draw Line Drawing
+
+If you have a lot of data points, it can be more performant to disable rendering of the line for a dataset and only draw points. Doing this means that there is less to draw on the canvas which will improve render performance.
+
+To disable lines:
+
+```javascript
+new Chart(ctx, {
+ type: 'line',
+ data: {
+ datasets: [{
+ showLine: false, // disable for a single dataset
+ }]
+ },
+ options: {
+ showLines: false, // disable for all datasets
+ }
+});
+```
+
+## Disable Animations
+
+If your charts have long render times, it is a good idea to disable animations. Doing so will mean that the chart needs to only be rendered once during an update instead of multiple times. This will have the effect of reducing CPU usage and improving general page performance.
+
+To disable animations
+
+```javascript
+new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ animation: {
+ duration: 0, // general animation time
+ },
+ hover: {
+ animationDuration: 0, // duration of animations when hovering an item
+ },
+ responsiveAnimationDuration: 0, // animation duration after a resize
+ }
+});
+```
diff --git a/contao/assets/chartjs/docs/charts/mixed.md b/contao/assets/chartjs/docs/charts/mixed.md
new file mode 100644
index 0000000..e7f43a2
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/mixed.md
@@ -0,0 +1,72 @@
+# Mixed Chart Types
+
+With Chart.js, it is possible to create mixed charts that are a combination of two or more different chart types. A common example is a bar chart that also includes a line dataset.
+
+Creating a mixed chart starts with the initialization of a basic chart.
+
+```javascript
+var myChart = new Chart(ctx, {
+ type: 'bar',
+ data: data,
+ options: options
+});
+```
+
+At this point we have a standard bar chart. Now we need to convert one of the datasets to a line dataset.
+
+```javascript
+var mixedChart = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ datasets: [{
+ label: 'Bar Dataset',
+ data: [10, 20, 30, 40]
+ }, {
+ label: 'Line Dataset',
+ data: [50, 50, 50, 50],
+
+ // Changes this dataset to become a line
+ type: 'line'
+ }],
+ labels: ['January', 'February', 'March', 'April']
+ },
+ options: options
+});
+```
+
+At this point we have a chart rendering how we'd like. It's important to note that the default options for a line chart are not merged in this case. Only the options for the default type are merged in. In this case, that means that the default options for a bar chart are merged because that is the type specified by the `type` field.
+
+{% chartjs %}
+{
+ "type": "bar",
+ "data": {
+ "labels": [
+ "January",
+ "February",
+ "March",
+ "April"
+ ],
+ "datasets": [{
+ "label": "Bar Dataset",
+ "data": [10, 20, 30, 40],
+ "borderColor": "rgb(255, 99, 132)",
+ "backgroundColor": "rgba(255, 99, 132, 0.2)"
+ }, {
+ "label": "Line Dataset",
+ "data": [50, 50, 50, 50],
+ "type": "line",
+ "fill": false,
+ "borderColor": "rgb(54, 162, 235)"
+ }]
+ },
+ "options": {
+ "scales": {
+ "yAxes": [{
+ "ticks": {
+ "beginAtZero": true
+ }
+ }]
+ }
+ }
+}
+{% endchartjs %}
diff --git a/contao/assets/chartjs/docs/charts/polar.md b/contao/assets/chartjs/docs/charts/polar.md
new file mode 100644
index 0000000..4c55556
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/polar.md
@@ -0,0 +1,95 @@
+# Polar Area
+
+Polar area charts are similar to pie charts, but each segment has the same angle - the radius of the segment differs depending on the value.
+
+This type of chart is often useful when we want to show a comparison data similar to a pie chart, but also show a scale of values for context.
+
+{% chartjs %}
+{
+ "type": "polarArea",
+ "data": {
+ "labels": [
+ "Red",
+ "Green",
+ "Yellow",
+ "Grey",
+ "Blue"
+ ],
+ "datasets": [{
+ "label": "My First Dataset",
+ "data": [11, 16, 7, 3, 14],
+ "backgroundColor": [
+ "rgb(255, 99, 132)",
+ "rgb(75, 192, 192)",
+ "rgb(255, 205, 86)",
+ "rgb(201, 203, 207)",
+ "rgb(54, 162, 235)"
+ ]
+ }]
+ },
+}
+{% endchartjs %}
+
+## Example Usage
+
+```javascript
+new Chart(ctx, {
+ data: data,
+ type: 'polarArea',
+ options: options
+});
+```
+
+## Dataset Properties
+
+The following options can be included in a polar area chart dataset to configure options for that specific dataset.
+
+| Name | Type | Description
+| ---- | ---- | -----------
+| `label` | `String` | The label for the dataset which appears in the legend and tooltips.
+| `backgroundColor` | `Color[]` | The fill color of the arcs in the dataset. See [Colors](../general/colors.md#colors)
+| `borderColor` | `Color[]` | The border color of the arcs in the dataset. See [Colors](../general/colors.md#colors)
+| `borderWidth` | `Number[]` | The border width of the arcs in the dataset.
+| `hoverBackgroundColor` | `Color[]` | The fill colour of the arcs when hovered.
+| `hoverBorderColor` | `Color[]` | The stroke colour of the arcs when hovered.
+| `hoverBorderWidth` | `Number[]` | The stroke width of the arcs when hovered.
+
+## Config Options
+
+These are the customisation options specific to Polar Area charts. These options are merged with the [global chart configuration options](#global-chart-configuration), and form the options of the chart.
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `startAngle` | `Number` | `-0.5 * Math.PI` | Starting angle to draw arcs for the first item in a dataset.
+| `animation.animateRotate` | `Boolean` | `true` | If true, the chart will animate in with a rotation animation. This property is in the `options.animation` object.
+| `animation.animateScale` | `Boolean` | `true` | If true, will animate scaling the chart from the center outwards.
+
+## Default Options
+
+We can also change these defaults values for each PolarArea type that is created, this object is available at `Chart.defaults.polarArea`. Changing the global options only affects charts created after the change. Existing charts are not changed.
+
+For example, to configure all new polar area charts with `animateScale = false` you would do:
+```javascript
+Chart.defaults.polarArea.animation.animateScale = false;
+```
+
+## Data Structure
+
+For a polar area chart, datasets need to contain an array of data points. The data points should be a number, Chart.js will total all of the numbers and calculate the relative proportion of each.
+
+You also need to specify an array of labels so that tooltips appear correctly for each slice.
+
+```javascript
+data = {
+ datasets: [{
+ data: [10, 20, 30]
+ }],
+
+ // These labels appear in the legend and in the tooltips when hovering different arcs
+ labels: [
+ 'Red',
+ 'Yellow',
+ 'Blue'
+ ]
+};
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/charts/radar.md b/contao/assets/chartjs/docs/charts/radar.md
new file mode 100644
index 0000000..dd5d47b
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/radar.md
@@ -0,0 +1,145 @@
+# Radar
+A radar chart is a way of showing multiple data points and the variation between them.
+
+They are often useful for comparing the points of two or more different data sets.
+
+{% chartjs %}
+{
+ "type": "radar",
+ "data": {
+ "labels": [
+ "Eating",
+ "Drinking",
+ "Sleeping",
+ "Designing",
+ "Coding",
+ "Cycling",
+ "Running"
+ ],
+ "datasets": [{
+ "label": "My First Dataset",
+ "data": [65, 59, 90, 81, 56, 55, 40],
+ "fill": true,
+ "backgroundColor": "rgba(255, 99, 132, 0.2)",
+ "borderColor": "rgb(255, 99, 132)",
+ "pointBackgroundColor": "rgb(255, 99, 132)",
+ "pointBorderColor": "#fff",
+ "pointHoverBackgroundColor": "#fff",
+ "pointHoverBorderColor": "rgb(255, 99, 132)",
+ "fill": true
+ }, {
+ "label": "My Second Dataset",
+ "data": [28, 48, 40, 19, 96, 27, 100],
+ "fill": true,
+ "backgroundColor": "rgba(54, 162, 235, 0.2)",
+ "borderColor": "rgb(54, 162, 235)",
+ "pointBackgroundColor": "rgb(54, 162, 235)",
+ "pointBorderColor": "#fff",
+ "pointHoverBackgroundColor": "#fff",
+ "pointHoverBorderColor": "rgb(54, 162, 235)",
+ "fill": true
+ }]
+ },
+ "options": {
+ "elements": {
+ "line": {
+ "tension": 0,
+ "borderWidth": 3
+ }
+ }
+ }
+}
+{% endchartjs %}
+
+## Example Usage
+```javascript
+var myRadarChart = new Chart(ctx, {
+ type: 'radar',
+ data: data,
+ options: options
+});
+```
+
+## Dataset Properties
+
+The radar chart allows a number of properties to be specified for each dataset. These are used to set display properties for a specific dataset. For example, the colour of a line is generally set this way.
+
+All point* properties can be specified as an array. If these are set to an array value, the first value applies to the first point, the second value to the second point, and so on.
+
+| Name | Type | Description
+| ---- | ---- | -----------
+| `label` | `String` | The label for the dataset which appears in the legend and tooltips.
+| `backgroundColor` | `Color/Color[]` | The fill color under the line. See [Colors](../general/colors.md#colors)
+| `borderColor` | `Color/Color[]` | The color of the line. See [Colors](../general/colors.md#colors)
+| `borderWidth` | `Number/Number[]` | The width of the line in pixels.
+| `borderDash` | `Number[]` | Length and spacing of dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
+| `borderDashOffset` | `Number` | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
+| `borderCapStyle` | `String` | Cap style of the line. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap)
+| `borderJoinStyle` | `String` | Line joint style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
+| `fill` | `Boolean/String` | How to fill the area under the line. See [area charts](area.md)
+| `lineTension` | `Number` | Bezier curve tension of the line. Set to 0 to draw straightlines.
+| `pointBackgroundColor` | `Color/Color[]` | The fill color for points.
+| `pointBorderColor` | `Color/Color[]` | The border color for points.
+| `pointBorderWidth` | `Number/Number[]` | The width of the point border in pixels.
+| `pointRadius` | `Number/Number[]` | The radius of the point shape. If set to 0, the point is not rendered.
+| `pointStyle` | `String/String[]/Image/Image[]` | Style of the point. [more...](#pointStyle)
+| `pointHitRadius` | `Number/Number[]` | The pixel size of the non-displayed point that reacts to mouse events.
+| `pointHoverBackgroundColor` | `Color/Color[]` | Point background color when hovered.
+| `pointHoverBorderColor` | `Color/Color[]` | Point border color when hovered.
+| `pointHoverBorderWidth` | `Number/Number[]` | Border width of point when hovered.
+| `pointHoverRadius` | `Number/Number[]` | The radius of the point when hovered.
+
+### pointStyle
+The style of point. Options are:
+* 'circle'
+* 'cross'
+* 'crossRot'
+* 'dash'.
+* 'line'
+* 'rect'
+* 'rectRounded'
+* 'rectRot'
+* 'star'
+* 'triangle'
+
+If the option is an image, that image is drawn on the canvas using [drawImage](https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/drawImage).
+
+## Configuration Options
+
+Unlike other charts, the radar chart has no chart specific options.
+
+## Scale Options
+
+The radar chart supports only a single scale. The options for this scale are defined in the `scale` property.
+
+```javascript
+options = {
+ scale: {
+ // Hides the scale
+ display: false
+ }
+};
+```
+
+## Default Options
+
+It is common to want to apply a configuration setting to all created radar charts. The global radar chart settings are stored in `Chart.defaults.radar`. Changing the global options only affects charts created after the change. Existing charts are not changed.
+
+## Data Structure
+
+The `data` property of a dataset for a radar chart is specified as a an array of numbers. Each point in the data array corresponds to the label at the same index on the x axis.
+
+```javascript
+data: [20, 10]
+```
+
+For a radar chart, to provide context of what each point means, we include an array of strings that show around each point in the chart.
+
+```javascript
+data: {
+ labels: ['Running', 'Swimming', 'Eating', 'Cycling'],
+ datasets: [{
+ data: [20, 10, 4, 2]
+ }]
+}
+```
diff --git a/contao/assets/chartjs/docs/charts/scatter.md b/contao/assets/chartjs/docs/charts/scatter.md
new file mode 100644
index 0000000..ef4e6f7
--- /dev/null
+++ b/contao/assets/chartjs/docs/charts/scatter.md
@@ -0,0 +1,49 @@
+# Scatter Chart
+
+Scatter charts are based on basic line charts with the x axis changed to a linear axis. To use a scatter chart, data must be passed as objects containing X and Y properties. The example below creates a scatter chart with 3 points.
+
+```javascript
+var scatterChart = new Chart(ctx, {
+ type: 'scatter',
+ data: {
+ datasets: [{
+ label: 'Scatter Dataset',
+ data: [{
+ x: -10,
+ y: 0
+ }, {
+ x: 0,
+ y: 10
+ }, {
+ x: 10,
+ y: 5
+ }]
+ }]
+ },
+ options: {
+ scales: {
+ xAxes: [{
+ type: 'linear',
+ position: 'bottom'
+ }]
+ }
+ }
+});
+```
+
+## Dataset Properties
+The scatter chart supports all of the same properties as the [line chart](./line.md#dataset-properties).
+
+## Data Structure
+
+Unlike the line chart where data can be supplied in two different formats, the scatter chart only accepts data in a point format.
+
+```javascript
+data: [{
+ x: 10,
+ y: 20
+ }, {
+ x: 15,
+ y: 10
+ }]
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/configuration/README.md b/contao/assets/chartjs/docs/configuration/README.md
new file mode 100644
index 0000000..7b71390
--- /dev/null
+++ b/contao/assets/chartjs/docs/configuration/README.md
@@ -0,0 +1,34 @@
+# Configuration
+
+The configuration is used to change how the chart behaves. There are properties to control styling, fonts, the legend, etc.
+
+## Global Configuration
+
+This concept was introduced in Chart.js 1.0 to keep configuration [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), and allow for changing options globally across chart types, avoiding the need to specify options for each instance, or the default for a particular chart type.
+
+Chart.js merges the options object passed to the chart with the global configuration using chart type defaults and scales defaults appropriately. This way you can be as specific as you would like in your individual chart configuration, while still changing the defaults for all chart types where applicable. The global general options are defined in `Chart.defaults.global`. The defaults for each chart type are discussed in the documentation for that chart type.
+
+The following example would set the hover mode to 'nearest' for all charts where this was not overridden by the chart type defaults or the options passed to the constructor on creation.
+
+```javascript
+Chart.defaults.global.hover.mode = 'nearest';
+
+// Hover mode is set to nearest because it was not overridden here
+var chartHoverModeNearest = new Chart(ctx, {
+ type: 'line',
+ data: data,
+});
+
+// This chart would have the hover mode that was passed in
+var chartDifferentHoverMode = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ hover: {
+ // Overrides the global setting
+ mode: 'index'
+ }
+ }
+})
+```
+
diff --git a/contao/assets/chartjs/docs/configuration/animations.md b/contao/assets/chartjs/docs/configuration/animations.md
new file mode 100644
index 0000000..92e273b
--- /dev/null
+++ b/contao/assets/chartjs/docs/configuration/animations.md
@@ -0,0 +1,96 @@
+# Animations
+
+Chart.js animates charts out of the box. A number of options are provided to configure how the animation looks and how long it takes
+
+## Animation Configuration
+
+The following animation options are available. The global options for are defined in `Chart.defaults.global.animation`.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `duration` | `Number` | `1000` | The number of milliseconds an animation takes.
+| `easing` | `String` | `'easeOutQuart'` | Easing function to use. [more...](#easing)
+| `onProgress` | `Function` | `null` | Callback called on each step of an animation. [more...](#animation-callbacks)
+| `onComplete` | `Function` | `null` | Callback called at the end of an animation. [more...](#animation-callbacks)
+
+## Easing
+ Available options are:
+* `'linear'`
+* `'easeInQuad'`
+* `'easeOutQuad'`
+* `'easeInOutQuad'`
+* `'easeInCubic'`
+* `'easeOutCubic'`
+* `'easeInOutCubic'`
+* `'easeInQuart'`
+* `'easeOutQuart'`
+* `'easeInOutQuart'`
+* `'easeInQuint'`
+* `'easeOutQuint'`
+* `'easeInOutQuint'`
+* `'easeInSine'`
+* `'easeOutSine'`
+* `'easeInOutSine'`
+* `'easeInExpo'`
+* `'easeOutExpo'`
+* `'easeInOutExpo'`
+* `'easeInCirc'`
+* `'easeOutCirc'`
+* `'easeInOutCirc'`
+* `'easeInElastic'`
+* `'easeOutElastic'`
+* `'easeInOutElastic'`
+* `'easeInBack'`
+* `'easeOutBack'`
+* `'easeInOutBack'`
+* `'easeInBounce'`
+* `'easeOutBounce'`
+* `'easeInOutBounce'`
+
+See [Robert Penner's easing equations](http://robertpenner.com/easing/).
+
+## Animation Callbacks
+
+The `onProgress` and `onComplete` callbacks are useful for synchronizing an external draw to the chart animation. The callback is passed a `Chart.Animation` instance:
+
+```javascript
+{
+ // Chart object
+ chart: Chart,
+
+ // Current Animation frame number
+ currentStep: Number,
+
+ // Number of animation frames
+ numSteps: Number,
+
+ // Animation easing to use
+ easing: String,
+
+ // Function that renders the chart
+ render: Function,
+
+ // User callback
+ onAnimationProgress: Function,
+
+ // User callback
+ onAnimationComplete: Function
+}
+```
+
+The following example fills a progress bar during the chart animation.
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ animation: {
+ onProgress: function(animation) {
+ progress.value = animation.animationObject.currentStep / animation.animationObject.numSteps;
+ }
+ }
+ }
+});
+```
+
+Another example usage of these callbacks can be found on [Github](https://github.com/chartjs/Chart.js/blob/master/samples/animation/progress-bar.html): this sample displays a progress bar showing how far along the animation is.
diff --git a/contao/assets/chartjs/docs/configuration/elements.md b/contao/assets/chartjs/docs/configuration/elements.md
new file mode 100644
index 0000000..0586a14
--- /dev/null
+++ b/contao/assets/chartjs/docs/configuration/elements.md
@@ -0,0 +1,69 @@
+# Elements
+
+While chart types provide settings to configure the styling of each dataset, you sometimes want to style **all datasets the same way**. A common example would be to stroke all of the bars in a bar chart with the same colour but change the fill per dataset. Options can be configured for four different types of elements: **[arc](#arc-configuration)**, **[lines](#line-configuration)**, **[points](#point-configuration)**, and **[rectangles](#rectangle-configuration)**. When set, these options apply to all objects of that type unless specifically overridden by the configuration attached to a dataset.
+
+## Global Configuration
+
+The element options can be specified per chart or globally. The global options for elements are defined in `Chart.defaults.global.elements`. For example, to set the border width of all bar charts globally you would do:
+
+```javascript
+Chart.defaults.global.elements.rectangle.borderWidth = 2;
+```
+
+## Point Configuration
+Point elements are used to represent the points in a line chart or a bubble chart.
+
+Global point options: `Chart.defaults.global.elements.point`
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `radius` | `Number` | `3` | Point radius.
+| `pointStyle` | `String` | `circle` | Point style.
+| `backgroundColor` | `Color` | `'rgba(0,0,0,0.1)'` | Point fill color.
+| `borderWidth` | `Number` | `1` | Point stroke width.
+| `borderColor` | `Color` | `'rgba(0,0,0,0.1)'` | Point stroke color.
+| `hitRadius` | `Number` | `1` | Extra radius added to point radius for hit detection.
+| `hoverRadius` | `Number` | `4` | Point radius when hovered.
+| `hoverBorderWidth` | `Number` | `1` | Stroke width when hovered.
+
+## Line Configuration
+Line elements are used to represent the line in a line chart.
+
+Global line options: `Chart.defaults.global.elements.line`
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `tension` | `Number` | `0.4` | Bézier curve tension (`0` for no Bézier curves).
+| `backgroundColor` | `Color` | `'rgba(0,0,0,0.1)'` | Line fill color.
+| `borderWidth` | `Number` | `3` | Line stroke width.
+| `borderColor` | `Color` | `'rgba(0,0,0,0.1)'` | Line stroke color.
+| `borderCapStyle` | `String` | `'butt'` | Line cap style (see [MDN](https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap)).
+| `borderDash` | `Array` | `[]` | Line dash (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)).
+| `borderDashOffset` | `Number` | `0` | Line dash offset (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)).
+| `borderJoinStyle` | `String` | `'miter` | Line join style (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)).
+| `capBezierPoints` | `Boolean` | `true` | `true` to keep Bézier control inside the chart, `false` for no restriction.
+| `fill` | `Boolean/String` | `true` | Fill location: `'zero'`, `'top'`, `'bottom'`, `true` (eq. `'zero'`) or `false` (no fill).
+| `stepped` | `Boolean` | `false` | `true` to show the line as a stepped line (`tension` will be ignored).
+
+## Rectangle Configuration
+Rectangle elements are used to represent the bars in a bar chart.
+
+Global rectangle options: `Chart.defaults.global.elements.rectangle`
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `backgroundColor` | `Color` | `'rgba(0,0,0,0.1)'` | Bar fill color.
+| `borderWidth` | `Number` | `0` | Bar stroke width.
+| `borderColor` | `Color` | `'rgba(0,0,0,0.1)'` | Bar stroke color.
+| `borderSkipped` | `String` | `'bottom'` | Skipped (excluded) border: `'bottom'`, `'left'`, `'top'` or `'right'`.
+
+## Arc Configuration
+Arcs are used in the polar area, doughnut and pie charts.
+
+Global arc options: `Chart.defaults.global.elements.arc`.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `backgroundColor` | `Color` | `'rgba(0,0,0,0.1)'` | Arc fill color.
+| `borderColor` | `Color` | `'#fff'` | Arc stroke color.
+| `borderWidth`| `Number` | `2` | Arc stroke width.
diff --git a/contao/assets/chartjs/docs/configuration/layout.md b/contao/assets/chartjs/docs/configuration/layout.md
new file mode 100644
index 0000000..fcd42fd
--- /dev/null
+++ b/contao/assets/chartjs/docs/configuration/layout.md
@@ -0,0 +1,29 @@
+# Layout Configuration
+
+The layout configuration is passed into the `options.layout` namespace. The global options for the chart layout is defined in `Chart.defaults.global.layout`.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `padding` | `Number` or `Object` | `0` | The padding to add inside the chart. [more...](#padding)
+
+## Padding
+If this value is a number, it is applied to all sides of the chart (left, top, right, bottom). If this value is an object, the `left` property defines the left padding. Similarly the `right`, `top`, and `bottom` properties can also be specified.
+
+Lets say you wanted to add 50px of padding to the left side of the chart canvas, you would do:
+
+```javascript
+let chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ layout: {
+ padding: {
+ left: 50,
+ right: 0,
+ top: 0,
+ bottom: 0
+ }
+ }
+ }
+});
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/configuration/legend.md b/contao/assets/chartjs/docs/configuration/legend.md
new file mode 100644
index 0000000..c398908
--- /dev/null
+++ b/contao/assets/chartjs/docs/configuration/legend.md
@@ -0,0 +1,166 @@
+# Legend Configuration
+
+The chart legend displays data about the datasets that area appearing on the chart.
+
+## Configuration options
+The legend configuration is passed into the `options.legend` namespace. The global options for the chart legend is defined in `Chart.defaults.global.legend`.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `display` | `Boolean` | `true` | is the legend shown
+| `position` | `String` | `'top'` | Position of the legend. [more...](#position)
+| `fullWidth` | `Boolean` | `true` | Marks that this box should take the full width of the canvas (pushing down other boxes). This is unlikely to need to be changed in day-to-day use.
+| `onClick` | `Function` | | A callback that is called when a click event is registered on a label item
+| `onHover` | `Function` | | A callback that is called when a 'mousemove' event is registered on top of a label item
+| `reverse` | `Boolean` | `false` | Legend will show datasets in reverse order.
+| `labels` | `Object` | | See the [Legend Label Configuration](#legend-label-configuration) section below.
+
+## Position
+Position of the legend. Options are:
+* `'top'`
+* `'left'`
+* `'bottom'`
+* `'right'`
+
+## Legend Label Configuration
+
+The legend label configuration is nested below the legend configuration using the `labels` key.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `boxWidth` | `Number` | `40` | width of coloured box
+| `fontSize` | `Number` | `12` | font size of text
+| `fontStyle` | `String` | `'normal'` | font style of text
+| `fontColor` | Color | `'#666'` | Color of text
+| `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family of legend text.
+| `padding` | `Number` | `10` | Padding between rows of colored boxes.
+| `generateLabels` | `Function` | | Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. See [Legend Item](#chart-configuration-legend-item-interface) for details.
+| `filter` | `Function` | `null` | Filters legend items out of the legend. Receives 2 parameters, a [Legend Item](#chart-configuration-legend-item-interface) and the chart data.
+| `usePointStyle` | `Boolean` | `false` | Label style will match corresponding point style (size is based on fontSize, boxWidth is not used in this case).
+
+## Legend Item Interface
+
+Items passed to the legend `onClick` function are the ones returned from `labels.generateLabels`. These items must implement the following interface.
+
+```javascript
+{
+ // Label that will be displayed
+ text: String,
+
+ // Fill style of the legend box
+ fillStyle: Color,
+
+ // If true, this item represents a hidden dataset. Label will be rendered with a strike-through effect
+ hidden: Boolean,
+
+ // For box border. See https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap
+ lineCap: String,
+
+ // For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
+ lineDash: Array[Number],
+
+ // For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
+ lineDashOffset: Number,
+
+ // For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin
+ lineJoin: String,
+
+ // Width of box border
+ lineWidth: Number,
+
+ // Stroke style of the legend box
+ strokeStyle: Color
+
+ // Point style of the legend box (only used if usePointStyle is true)
+ pointStyle: String
+}
+```
+
+## Example
+
+The following example will create a chart with the legend enabled and turn all of the text red in color.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'bar',
+ data: data,
+ options: {
+ legend: {
+ display: true,
+ labels: {
+ fontColor: 'rgb(255, 99, 132)'
+ }
+ }
+}
+});
+```
+
+## Custom On Click Actions
+
+It can be common to want to trigger different behaviour when clicking an item in the legend. This can be easily achieved using a callback in the config object.
+
+The default legend click handler is:
+```javascript
+function(e, legendItem) {
+ var index = legendItem.datasetIndex;
+ var ci = this.chart;
+ var meta = ci.getDatasetMeta(index);
+
+ // See controller.isDatasetVisible comment
+ meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
+
+ // We hid a dataset ... rerender the chart
+ ci.update();
+}
+```
+
+Lets say we wanted instead to link the display of the first two datasets. We could change the click handler accordingly.
+
+```javascript
+var defaultLegendClickHandler = Chart.defaults.global.legend.onClick;
+var newLegendClickHandler = function (e, legendItem) {
+ var index = legendItem.datasetIndex;
+
+ if (index > 1) {
+ // Do the original logic
+ defaultLegendClickHandler(e, legendItem);
+ } else {
+ let ci = this.chart;
+ [ci.getDatasetMeta(0),
+ ci.getDatasetMeta(1)].forEach(function(meta) {
+ meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
+ });
+ ci.update();
+ }
+};
+
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ legend: {
+
+ }
+ }
+});
+```
+
+Now when you click the legend in this chart, the visibility of the first two datasets will be linked together.
+
+## HTML Legends
+
+Sometimes you need a very complex legend. In these cases, it makes sense to generate an HTML legend. Charts provide a `generateLegend()` method on their prototype that returns an HTML string for the legend.
+
+To configure how this legend is generated, you can change the `legendCallback` config property.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ legendCallback: function(chart) {
+ // Return the HTML string here.
+ }
+ }
+});
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/configuration/title.md b/contao/assets/chartjs/docs/configuration/title.md
new file mode 100644
index 0000000..a02e6b6
--- /dev/null
+++ b/contao/assets/chartjs/docs/configuration/title.md
@@ -0,0 +1,41 @@
+# Title
+
+The chart title defines text to draw at the top of the chart.
+
+## Title Configuration
+The title configuration is passed into the `options.title` namespace. The global options for the chart title is defined in `Chart.defaults.global.title`.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `display` | `Boolean` | `false` | is the title shown
+| `position` | `String` | `'top'` | Position of title. [more...](#position)
+| `fontSize` | `Number` | `12` | Font size
+| `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the title text.
+| `fontColor` | Color | `'#666'` | Font color
+| `fontStyle` | `String` | `'bold'` | Font style
+| `padding` | `Number` | `10` | Number of pixels to add above and below the title text.
+| `text` | `String` | `''` | Title text ti display
+
+### Position
+Possible title position values are:
+* `'top'`
+* `'left'`
+* `'bottom'`
+* `'right'`
+
+## Example Usage
+
+The example below would enable a title of 'Custom Chart Title' on the chart that is created.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ title: {
+ display: true,
+ text: 'Custom Chart Title'
+ }
+ }
+})
+```
diff --git a/contao/assets/chartjs/docs/configuration/tooltip.md b/contao/assets/chartjs/docs/configuration/tooltip.md
new file mode 100644
index 0000000..21387f1
--- /dev/null
+++ b/contao/assets/chartjs/docs/configuration/tooltip.md
@@ -0,0 +1,293 @@
+# Tooltips
+
+## Tooltip Configuration
+
+The tooltip configuration is passed into the `options.tooltips` namespace. The global options for the chart tooltips is defined in `Chart.defaults.global.tooltips`.
+
+| Name | Type | Default | Description
+| -----| ---- | --------| -----------
+| `enabled` | `Boolean` | `true` | Are tooltips enabled
+| `custom` | `Function` | `null` | See [custom tooltip](#custom-tooltips) section.
+| `mode` | `String` | `'nearest'` | Sets which elements appear in the tooltip. [more...](../general/interactions/modes.md#interaction-modes).
+| `intersect` | `Boolean` | `true` | if true, the tooltip mode applies only when the mouse position intersects with an element. If false, the mode will be applied at all times.
+| `position` | `String` | `'average'` | The mode for positioning the tooltip. [more...](#position-modes)
+| `callbacks` | `Object` | | See the [callbacks section](#tooltip-callbacks)
+| `itemSort` | `Function` | | Sort tooltip items. [more...](#sort-callback)
+| `filter` | `Function` | | Filter tooltip items. [more...](#filter-callback)
+| `backgroundColor` | Color | `'rgba(0,0,0,0.8)'` | Background color of the tooltip.
+| `titleFontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | title font
+| `titleFontSize` | `Number` | `12` | Title font size
+| `titleFontStyle` | `String` | `'bold'` | Title font style
+| `titleFontColor` | Color | `'#fff'` | Title font color
+| `titleSpacing` | `Number` | `2` | Spacing to add to top and bottom of each title line.
+| `titleMarginBottom` | `Number` | `6` | Margin to add on bottom of title section.
+| `bodyFontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | body line font
+| `bodyFontSize` | `Number` | `12` | Body font size
+| `bodyFontStyle` | `String` | `'normal'` | Body font style
+| `bodyFontColor` | Color | `'#fff'` | Body font color
+| `bodySpacing` | `Number` | `2` | Spacing to add to top and bottom of each tooltip item.
+| `footerFontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | footer font
+| `footerFontSize` | `Number` | `12` | Footer font size
+| `footerFontStyle` | `String` | `'bold'` | Footer font style
+| `footerFontColor` | Color | `'#fff'` | Footer font color
+| `footerSpacing` | `Number` | `2` | Spacing to add to top and bottom of each fotter line.
+| `footerMarginTop` | `Number` | `6` | Margin to add before drawing the footer.
+| `xPadding` | `Number` | `6` | Padding to add on left and right of tooltip.
+| `yPadding` | `Number` | `6` | Padding to add on top and bottom of tooltip.
+| `caretPadding` | `Number` | `2` | Extra distance to move the end of the tooltip arrow away from the tooltip point.
+| `caretSize` | `Number` | `5` | Size, in px, of the tooltip arrow.
+| `cornerRadius` | `Number` | `6` | Radius of tooltip corner curves.
+| `multiKeyBackground` | Color | `'#fff'` | Color to draw behind the colored boxes when multiple items are in the tooltip
+| `displayColors` | `Boolean` | `true` | if true, color boxes are shown in the tooltip
+| `borderColor` | Color | `'rgba(0,0,0,0)'` | Color of the border
+| `borderWidth` | `Number` | `0` | Size of the border
+
+### Position Modes
+ Possible modes are:
+* 'average'
+* 'nearest'
+
+'average' mode will place the tooltip at the average position of the items displayed in the tooltip. 'nearest' will place the tooltip at the position of the element closest to the event position.
+
+New modes can be defined by adding functions to the Chart.Tooltip.positioners map.
+
+### Sort Callback
+
+Allows sorting of [tooltip items](#chart-configuration-tooltip-item-interface). Must implement at minimum a function that can be passed to [Array.prototype.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort). This function can also accept a third parameter that is the data object passed to the chart.
+
+### Filter Callback
+
+Allows filtering of [tooltip items](#chart-configuration-tooltip-item-interface). Must implement at minimum a function that can be passed to [Array.prototype.filter](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter). This function can also accept a second parameter that is the data object passed to the chart.
+
+## Tooltip Callbacks
+
+The tooltip label configuration is nested below the tooltip configuration using the `callbacks` key. The tooltip has the following callbacks for providing text. For all functions, 'this' will be the tooltip object created from the Chart.Tooltip constructor.
+
+All functions are called with the same arguments: a [tooltip item](#chart-configuration-tooltip-item-interface) and the data object passed to the chart. All functions must return either a string or an array of strings. Arrays of strings are treated as multiple lines of text.
+
+| Name | Arguments | Description
+| ---- | --------- | -----------
+| `beforeTitle` | `Array[tooltipItem], data` | Returns the text to render before the title.
+| `title` | `Array[tooltipItem], data` | Returns text to render as the title of the tooltip.
+| `afterTitle` | `Array[tooltipItem], data` | Returns text to render after the title.
+| `beforeBody` | `Array[tooltipItem], data` | Returns text to render before the body section.
+| `beforeLabel` | `tooltipItem, data` | Returns text to render before an individual label. This will be called for each item in the tooltip.
+| `label` | `tooltipItem, data` | Returns text to render for an individual item in the tooltip.
+| `labelColor` | `tooltipItem, chart` | Returns the colors to render for the tooltip item. [more...](#label-color-callback)
+| `afterLabel` | `tooltipItem, data` | Returns text to render after an individual label.
+| `afterBody` | `Array[tooltipItem], data` | Returns text to render after the body section
+| `beforeFooter` | `Array[tooltipItem], data` | Returns text to render before the footer section.
+| `footer` | `Array[tooltipItem], data` | Returns text to render as the footer of the tooltip.
+| `afterFooter` | `Array[tooltipItem], data` | Text to render after the footer section
+
+### Label Color Callback
+
+For example, to return a red box for each item in the tooltip you could do:
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ tooltips: {
+ callbacks: {
+ labelColor: function(tooltipItem, chart) {
+ return {
+ borderColor: 'rgb(255, 0, 0)',
+ backgroundColor: 'rgb(255, 0, 0)'
+ }
+ }
+ }
+ }
+ }
+});
+```
+
+
+### Tooltip Item Interface
+
+The tooltip items passed to the tooltip callbacks implement the following interface.
+
+```javascript
+{
+ // X Value of the tooltip as a string
+ xLabel: String,
+
+ // Y value of the tooltip as a string
+ yLabel: String,
+
+ // Index of the dataset the item comes from
+ datasetIndex: Number,
+
+ // Index of this data item in the dataset
+ index: Number,
+
+ // X position of matching point
+ x: Number,
+
+ // Y position of matching point
+ y: Number,
+}
+```
+
+## External (Custom) Tooltips
+
+Custom tooltips allow you to hook into the tooltip rendering process so that you can render the tooltip in your own custom way. Generally this is used to create an HTML tooltip instead of an oncanvas one. You can enable custom tooltips in the global or chart configuration like so:
+
+```javascript
+var myPieChart = new Chart(ctx, {
+ type: 'pie',
+ data: data,
+ options: {
+ tooltips: {
+ custom: function(tooltipModel) {
+ // Tooltip Element
+ var tooltipEl = document.getElementById('chartjs-tooltip');
+
+ // Create element on first render
+ if (!tooltipEl) {
+ tooltipEl = document.createElement('div');
+ tooltipEl.id = 'chartjs-tooltip';
+ tooltipEl.innerHTML = ""
+ document.body.appendChild(tooltipEl);
+ }
+
+ // Hide if no tooltip
+ if (tooltipModel.opacity === 0) {
+ tooltipEl.style.opacity = 0;
+ return;
+ }
+
+ // Set caret Position
+ tooltipEl.classList.remove('above', 'below', 'no-transform');
+ if (tooltipModel.yAlign) {
+ tooltipEl.classList.add(tooltipModel.yAlign);
+ } else {
+ tooltipEl.classList.add('no-transform');
+ }
+
+ function getBody(bodyItem) {
+ return bodyItem.lines;
+ }
+
+ // Set Text
+ if (tooltipModel.body) {
+ var titleLines = tooltipModel.title || [];
+ var bodyLines = tooltipModel.body.map(getBody);
+
+ var innerHtml = '';
+
+ titleLines.forEach(function(title) {
+ innerHtml += '' + title + ' ';
+ });
+ innerHtml += ' ';
+
+ bodyLines.forEach(function(body, i) {
+ var colors = tooltipModel.labelColors[i];
+ var style = 'background:' + colors.backgroundColor;
+ style += '; border-color:' + colors.borderColor;
+ style += '; border-width: 2px';
+ var span = ' ';
+ innerHtml += '' + span + body + ' ';
+ });
+ innerHtml += ' ';
+
+ var tableRoot = tooltipEl.querySelector('table');
+ tableRoot.innerHTML = innerHtml;
+ }
+
+ // `this` will be the overall tooltip
+ var position = this._chart.canvas.getBoundingClientRect();
+
+ // Display, position, and set styles for font
+ tooltipEl.style.opacity = 1;
+ tooltipEl.style.left = position.left + tooltipModel.caretX + 'px';
+ tooltipEl.style.top = position.top + tooltipModel.caretY + 'px';
+ tooltipEl.style.fontFamily = tooltipModel._fontFamily;
+ tooltipEl.style.fontSize = tooltipModel.fontSize;
+ tooltipEl.style.fontStyle = tooltipModel._fontStyle;
+ tooltipEl.style.padding = tooltipModel.yPadding + 'px ' + tooltipModel.xPadding + 'px';
+ }
+ }
+ }
+});
+```
+
+See `samples/tooltips/line-customTooltips.html` for examples on how to get started.
+
+## Tooltip Model
+The tooltip model contains parameters that can be used to render the tooltip.
+
+```javascript
+{
+ // The items that we are rendering in the tooltip. See Tooltip Item Interface section
+ dataPoints: TooltipItem[],
+
+ // Positioning
+ xPadding: Number,
+ yPadding: Number,
+ xAlign: String,
+ yAlign: String,
+
+ // X and Y properties are the top left of the tooltip
+ x: Number,
+ y: Number,
+ width: Number,
+ height: Number,
+ // Where the tooltip points to
+ caretX: Number,
+ caretY: Number,
+
+ // Body
+ // The body lines that need to be rendered
+ // Each pbject contains 3 parameters
+ // before: String[] // lines of text before the line with the color square
+ // lines: String[], // lines of text to render as the main item with color square
+ // after: String[], // lines of text to render after the main lines
+ body: Object[],
+ // lines of text that appear after the title but before the body
+ beforeBody: String[],
+ // line of text that appear after the body and before the footer
+ afterBody: String[],
+ bodyFontColor: Color,
+ _bodyFontFamily: String,
+ _bodyFontStyle: String,
+ _bodyAlign: String,
+ bodyFontSize: Number,
+ bodySpacing: Number,
+
+ // Title
+ // lines of text that form the title
+ title: String[],
+ titleFontColor: Color,
+ _titleFontFamily: String,
+ _titleFontStyle: String,
+ titleFontSize: Number,
+ _titleAlign: String,
+ titleSpacing: Number,
+ titleMarginBottom: Number,
+
+ // Footer
+ // lines of text that form the footer
+ footer: String[],
+ footerFontColor: Color,
+ _footerFontFamily: String,
+ _footerFontStyle: String,
+ footerFontSize: Number,
+ _footerAlign: String,
+ footerSpacing: Number,
+ footerMarginTop: Number,
+
+ // Appearance
+ caretSize: Number,
+ cornerRadius: Number,
+ backgroundColor: Color,
+
+ // colors to render for each item in body[]. This is the color of the squares in the tooltip
+ labelColors: Color[],
+
+ // 0 opacity is a hidden tooltip
+ opacity: Number,
+ legendColorBackground: Color,
+ displayColors: Boolean,
+}
+```
diff --git a/contao/assets/chartjs/docs/developers/README.md b/contao/assets/chartjs/docs/developers/README.md
new file mode 100644
index 0000000..f8d6e97
--- /dev/null
+++ b/contao/assets/chartjs/docs/developers/README.md
@@ -0,0 +1,22 @@
+# Developers
+Developer features allow extending and enhancing Chart.js in many different ways.
+
+# Browser support
+
+Chart.js offers support for all browsers where canvas is supported.
+
+Browser support for the canvas element is available in all modern & major mobile browsers. [CanIUse](http://caniuse.com/#feat=canvas)
+
+Thanks to [BrowserStack](https://browserstack.com) for allowing our team to test on thousands of browsers.
+
+# Previous versions
+
+Version 2 has a completely different API than earlier versions.
+
+Most earlier version options have current equivalents or are the same.
+
+Please use the documentation that is available on [chartjs.org](http://www.chartjs.org/docs/) for the current version of Chart.js.
+
+Please note - documentation for previous versions are available on the GitHub repo.
+
+- [1.x Documentation](https://github.com/chartjs/Chart.js/tree/v1.1.1/docs)
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/developers/api.md b/contao/assets/chartjs/docs/developers/api.md
new file mode 100644
index 0000000..714cb58
--- /dev/null
+++ b/contao/assets/chartjs/docs/developers/api.md
@@ -0,0 +1,145 @@
+# Chart Prototype Methods
+
+For each chart, there are a set of global prototype methods on the shared `ChartType` which you may find useful. These are available on all charts created with Chart.js, but for the examples, let's use a line chart we've made.
+
+```javascript
+// For example:
+var myLineChart = new Chart(ctx, config);
+```
+
+## .destroy()
+
+Use this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js.
+This must be called before the canvas is reused for a new chart.
+
+```javascript
+// Destroys a specific chart instance
+myLineChart.destroy();
+```
+
+## .update(duration, lazy)
+
+Triggers an update of the chart. This can be safely called after updating the data object. This will update all scales, legends, and then re-render the chart.
+
+```javascript
+// duration is the time for the animation of the redraw in milliseconds
+// lazy is a boolean. if true, the animation can be interrupted by other animations
+myLineChart.data.datasets[0].data[2] = 50; // Would update the first dataset's value of 'March' to be 50
+myLineChart.update(); // Calling update now animates the position of March from 90 to 50.
+```
+
+> **Note:** replacing the data reference (e.g. `myLineChart.data = {datasets: [...]}` only works starting **version 2.6**. Prior that, replacing the entire data object could be achieved with the following workaround: `myLineChart.config.data = {datasets: [...]}`.
+
+See [Updating Charts](updates.md) for more details.
+
+## .reset()
+
+Reset the chart to it's state before the initial animation. A new animation can then be triggered using `update`.
+
+```javascript
+myLineChart.reset();
+```
+
+## .render(duration, lazy)
+
+Triggers a redraw of all chart elements. Note, this does not update elements for new data. Use `.update()` in that case.
+
+```javascript
+// duration is the time for the animation of the redraw in milliseconds
+// lazy is a boolean. if true, the animation can be interrupted by other animations
+myLineChart.render(duration, lazy);
+```
+
+## .stop()
+
+Use this to stop any current animation loop. This will pause the chart during any current animation frame. Call `.render()` to re-animate.
+
+```javascript
+// Stops the charts animation loop at its current frame
+myLineChart.stop();
+// => returns 'this' for chainability
+```
+
+## .resize()
+
+Use this to manually resize the canvas element. This is run each time the canvas container is resized, but you can call this method manually if you change the size of the canvas nodes container element.
+
+```javascript
+// Resizes & redraws to fill its container element
+myLineChart.resize();
+// => returns 'this' for chainability
+```
+
+## .clear()
+
+Will clear the chart canvas. Used extensively internally between animation frames, but you might find it useful.
+
+```javascript
+// Will clear the canvas that myLineChart is drawn on
+myLineChart.clear();
+// => returns 'this' for chainability
+```
+
+## .toBase64Image()
+
+This returns a base 64 encoded string of the chart in it's current state.
+
+```javascript
+myLineChart.toBase64Image();
+// => returns png data url of the image on the canvas
+```
+
+## .generateLegend()
+
+Returns an HTML string of a legend for that chart. The legend is generated from the `legendCallback` in the options.
+
+```javascript
+myLineChart.generateLegend();
+// => returns HTML string of a legend for this chart
+```
+
+## .getElementAtEvent(e)
+
+Calling `getElementAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the single element at the event position. If there are multiple items within range, only the first is returned. The value returned from this method is an array with a single parameter. An array is used to keep a consistent API between the `get*AtEvent` methods.
+
+```javascript
+myLineChart.getElementAtEvent(e);
+// => returns the first element at the event point.
+```
+
+## .getElementsAtEvent(e)
+
+Looks for the element under the event point, then returns all elements at the same data index. This is used internally for 'label' mode highlighting.
+
+Calling `getElementsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event.
+
+```javascript
+canvas.onclick = function(evt){
+ var activePoints = myLineChart.getElementsAtEvent(evt);
+ // => activePoints is an array of points on the canvas that are at the same position as the click event.
+};
+```
+
+This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application.
+
+## .getDatasetAtEvent(e)
+
+Looks for the element under the event point, then returns all elements from that dataset. This is used internally for 'dataset' mode highlighting
+
+```javascript
+myLineChart.getDatasetAtEvent(e);
+// => returns an array of elements
+```
+
+## .getDatasetMeta(index)
+
+Looks for the dataset that matches the current index and returns that metadata. This returned data has all of the metadata that is used to construct the chart.
+
+The `data` property of the metadata will contain information about each point, rectangle, etc. depending on the chart type.
+
+Extensive examples of usage are available in the [Chart.js tests](https://github.com/chartjs/Chart.js/tree/master/test).
+
+```javascript
+var meta = myChart.getDatasetMeta(0);
+var x = meta.data[0]._model.x
+```
diff --git a/contao/assets/chartjs/docs/developers/axes.md b/contao/assets/chartjs/docs/developers/axes.md
new file mode 100644
index 0000000..8d12019
--- /dev/null
+++ b/contao/assets/chartjs/docs/developers/axes.md
@@ -0,0 +1,131 @@
+# New Axes
+
+Axes in Chart.js can be individually extended. Axes should always derive from Chart.Scale but this is not a mandatory requirement.
+
+```javascript
+let MyScale = Chart.Scale.extend({
+ /* extensions ... */
+});
+
+// MyScale is now derived from Chart.Scale
+```
+
+Once you have created your scale class, you need to register it with the global chart object so that it can be used. A default config for the scale may be provided when registering the constructor. The first parameter to the register function is a string key that is used later to identify which scale type to use for a chart.
+
+```javascript
+Chart.scaleService.registerScaleType('myScale', MyScale, defaultConfigObject);
+```
+
+To use the new scale, simply pass in the string key to the config when creating a chart.
+
+```javascript
+var lineChart = new Chart(ctx, {
+ data: data,
+ type: 'line',
+ options: {
+ scales: {
+ yAxes: [{
+ type: 'myScale' // this is the same key that was passed to the registerScaleType function
+ }]
+ }
+ }
+})
+```
+
+## Scale Properties
+
+Scale instances are given the following properties during the fitting process.
+
+```javascript
+{
+ left: Number, // left edge of the scale bounding box
+ right: Number, // right edge of the bounding box'
+ top: Number,
+ bottom: Number,
+ width: Number, // the same as right - left
+ height: Number, // the same as bottom - top
+
+ // Margin on each side. Like css, this is outside the bounding box.
+ margins: {
+ left: Number,
+ right: Number,
+ top: Number,
+ bottom: Number,
+ },
+
+ // Amount of padding on the inside of the bounding box (like CSS)
+ paddingLeft: Number,
+ paddingRight: Number,
+ paddingTop: Number,
+ paddingBottom: Number,
+}
+```
+
+## Scale Interface
+To work with Chart.js, custom scale types must implement the following interface.
+
+```javascript
+{
+ // Determines the data limits. Should set this.min and this.max to be the data max/min
+ determineDataLimits: function() {},
+
+ // Generate tick marks. this.chart is the chart instance. The data object can be accessed as this.chart.data
+ // buildTicks() should create a ticks array on the axis instance, if you intend to use any of the implementations from the base class
+ buildTicks: function() {},
+
+ // Get the value to show for the data at the given index of the the given dataset, ie this.chart.data.datasets[datasetIndex].data[index]
+ getLabelForIndex: function(index, datasetIndex) {},
+
+ // Get the pixel (x coordinate for horizontal axis, y coordinate for vertical axis) for a given value
+ // @param index: index into the ticks array
+ // @param includeOffset: if true, get the pixel halway between the given tick and the next
+ getPixelForTick: function(index, includeOffset) {},
+
+ // Get the pixel (x coordinate for horizontal axis, y coordinate for vertical axis) for a given value
+ // @param value : the value to get the pixel for
+ // @param index : index into the data array of the value
+ // @param datasetIndex : index of the dataset the value comes from
+ // @param includeOffset : if true, get the pixel halway between the given tick and the next
+ getPixelForValue: function(value, index, datasetIndex, includeOffset) {}
+
+ // Get the value for a given pixel (x coordinate for horizontal axis, y coordinate for vertical axis)
+ // @param pixel : pixel value
+ getValueForPixel: function(pixel) {}
+}
+```
+
+Optionally, the following methods may also be overwritten, but an implementation is already provided by the `Chart.Scale` base class.
+
+```javascript
+ // Transform the ticks array of the scale instance into strings. The default implementation simply calls this.options.ticks.callback(numericalTick, index, ticks);
+ convertTicksToLabels: function() {},
+
+ // Determine how much the labels will rotate by. The default implementation will only rotate labels if the scale is horizontal.
+ calculateTickRotation: function() {},
+
+ // Fits the scale into the canvas.
+ // this.maxWidth and this.maxHeight will tell you the maximum dimensions the scale instance can be. Scales should endeavour to be as efficient as possible with canvas space.
+ // this.margins is the amount of space you have on either side of your scale that you may expand in to. This is used already for calculating the best label rotation
+ // You must set this.minSize to be the size of your scale. It must be an object containing 2 properties: width and height.
+ // You must set this.width to be the width and this.height to be the height of the scale
+ fit: function() {},
+
+ // Draws the scale onto the canvas. this.(left|right|top|bottom) will have been populated to tell you the area on the canvas to draw in
+ // @param chartArea : an object containing four properties: left, right, top, bottom. This is the rectangle that lines, bars, etc will be drawn in. It may be used, for example, to draw grid lines.
+ draw: function(chartArea) {},
+```
+
+The Core.Scale base class also has some utility functions that you may find useful.
+```javascript
+{
+ // Returns true if the scale instance is horizontal
+ isHorizontal: function() {},
+
+ // Get the correct value from the value from this.chart.data.datasets[x].data[]
+ // If dataValue is an object, returns .x or .y depending on the return of isHorizontal()
+ // If the value is undefined, returns NaN
+ // Otherwise returns the value.
+ // Note that in all cases, the returned value is not guaranteed to be a Number
+ getRightValue: function(dataValue) {},
+}
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/developers/charts.md b/contao/assets/chartjs/docs/developers/charts.md
new file mode 100644
index 0000000..f4c9a97
--- /dev/null
+++ b/contao/assets/chartjs/docs/developers/charts.md
@@ -0,0 +1,116 @@
+# New Charts
+
+Chart.js 2.0 introduces the concept of controllers for each dataset. Like scales, new controllers can be written as needed.
+
+```javascript
+Chart.controllers.MyType = Chart.DatasetController.extend({
+
+});
+
+
+// Now we can create a new instance of our chart, using the Chart.js API
+new Chart(ctx, {
+ // this is the string the constructor was registered at, ie Chart.controllers.MyType
+ type: 'MyType',
+ data: data,
+ options: options
+});
+```
+
+## Dataset Controller Interface
+
+Dataset controllers must implement the following interface.
+
+```javascript
+{
+ // Create elements for each piece of data in the dataset. Store elements in an array on the dataset as dataset.metaData
+ addElements: function() {},
+
+ // Create a single element for the data at the given index and reset its state
+ addElementAndReset: function(index) {},
+
+ // Draw the representation of the dataset
+ // @param ease : if specified, this number represents how far to transition elements. See the implementation of draw() in any of the provided controllers to see how this should be used
+ draw: function(ease) {},
+
+ // Remove hover styling from the given element
+ removeHoverStyle: function(element) {},
+
+ // Add hover styling to the given element
+ setHoverStyle: function(element) {},
+
+ // Update the elements in response to new data
+ // @param reset : if true, put the elements into a reset state so they can animate to their final values
+ update: function(reset) {},
+}
+```
+
+The following methods may optionally be overridden by derived dataset controllers
+```javascript
+{
+ // Initializes the controller
+ initialize: function(chart, datasetIndex) {},
+
+ // Ensures that the dataset represented by this controller is linked to a scale. Overridden to helpers.noop in the polar area and doughnut controllers as these
+ // chart types using a single scale
+ linkScales: function() {},
+
+ // Called by the main chart controller when an update is triggered. The default implementation handles the number of data points changing and creating elements appropriately.
+ buildOrUpdateElements: function() {}
+}
+```
+
+## Extending Existing Chart Types
+
+Extending or replacing an existing controller type is easy. Simply replace the constructor for one of the built in types with your own.
+
+The built in controller types are:
+* `Chart.controllers.line`
+* `Chart.controllers.bar`
+* `Chart.controllers.radar`
+* `Chart.controllers.doughnut`
+* `Chart.controllers.polarArea`
+* `Chart.controllers.bubble`
+
+For example, to derive a new chart type that extends from a bubble chart, you would do the following.
+
+```javascript
+// Sets the default config for 'derivedBubble' to be the same as the bubble defaults.
+// We look for the defaults by doing Chart.defaults[chartType]
+// It looks like a bug exists when the defaults don't exist
+Chart.defaults.derivedBubble = Chart.defaults.bubble;
+
+// I think the recommend using Chart.controllers.bubble.extend({ extensions here });
+var custom = Chart.controllers.bubble.extend({
+ draw: function(ease) {
+ // Call super method first
+ Chart.controllers.bubble.prototype.draw.call(this, ease);
+
+ // Now we can do some custom drawing for this dataset. Here we'll draw a red box around the first point in each dataset
+ var meta = this.getMeta();
+ var pt0 = meta.data[0];
+ var radius = pt0._view.radius;
+
+ var ctx = this.chart.chart.ctx;
+ ctx.save();
+ ctx.strokeStyle = 'red';
+ ctx.lineWidth = 1;
+ ctx.strokeRect(pt0._view.x - radius, pt0._view.y - radius, 2 * radius, 2 * radius);
+ ctx.restore();
+ }
+});
+
+// Stores the controller so that the chart initialization routine can look it up with
+// Chart.controllers[type]
+Chart.controllers.derivedBubble = custom;
+
+// Now we can create and use our new chart type
+new Chart(ctx, {
+ type: 'derivedBubble',
+ data: data,
+ options: options,
+});
+```
+
+### Bar Controller
+The bar controller has a special property that you should be aware of. To correctly calculate the width of a bar, the controller must determine the number of datasets that map to bars. To do this, the bar controller attaches a property `bar` to the dataset during initialization. If you are creating a replacement or updated bar controller, you should do the same. This will ensure that charts with regular bars and your new derived bars will work seamlessly.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/developers/contributing.md b/contao/assets/chartjs/docs/developers/contributing.md
new file mode 100644
index 0000000..ee08b4d
--- /dev/null
+++ b/contao/assets/chartjs/docs/developers/contributing.md
@@ -0,0 +1,55 @@
+# Contributing
+
+New contributions to the library are welcome, but we ask that you please follow these guidelines:
+
+- Use tabs for indentation, not spaces.
+- Only change the individual files in `/src`.
+- Check that your code will pass `eslint` code standards, `gulp lint` will run this for you.
+- Check that your code will pass tests, `gulp test` will run tests for you.
+- Keep pull requests concise, and document new functionality in the relevant `.md` file.
+- Consider whether your changes are useful for all users, or if creating a Chart.js [plugin](plugins.md) would be more appropriate.
+
+# Joining the project
+
+ Active committers and contributors are invited to introduce yourself and request commit access to this project. We have a very active Slack community that you can join [here](https://chart-js-automation.herokuapp.com/). If you think you can help, we'd love to have you!
+
+# Building and Testing
+
+Chart.js uses gulp to build the library into a single JavaScript file.
+
+Firstly, we need to ensure development dependencies are installed. With node and npm installed, after cloning the Chart.js repo to a local directory, and navigating to that directory in the command line, we can run the following:
+
+```bash
+> npm install
+> npm install -g gulp
+```
+
+This will install the local development dependencies for Chart.js, along with a CLI for the JavaScript task runner gulp .
+
+The following commands are now available from the repository root:
+
+```bash
+> gulp build // build Chart.js in ./dist
+> gulp unittest // run tests from ./test/specs
+> gulp unittest --watch // run tests and watch for source changes
+> gulp unittest --coverage // run tests and generate coverage reports in ./coverage
+> gulp lint // perform code linting (ESLint)
+> gulp test // perform code linting and run unit tests
+> gulp docs // build the documentation in ./dist/docs
+```
+
+More information can be found in [gulpfile.js](https://github.com/chartjs/Chart.js/blob/master/gulpfile.js).
+
+# Bugs and Issues
+
+Please report these on the GitHub page - at github.com/chartjs/Chart.js . Please do not use issues for support requests. For help using Chart.js, please take a look at the [`chartjs`](http://stackoverflow.com/questions/tagged/chartjs) tag on Stack Overflow.
+
+Well structured, detailed bug reports are hugely valuable for the project.
+
+Guidelines for reporting bugs:
+
+ - Check the issue search to see if it has already been reported
+ - Isolate the problem to a simple test case
+ - Please include a demonstration of the bug on a website such as [JS Bin](http://jsbin.com/), [JS Fiddle](http://jsfiddle.net/), or [Codepen](http://codepen.io/pen/). ([Template](http://codepen.io/pen?template=JXVYzq))
+
+Please provide any additional details associated with the bug, if it's browser or screen density specific, or only happens with a certain configuration or data.
diff --git a/contao/assets/chartjs/docs/developers/plugins.md b/contao/assets/chartjs/docs/developers/plugins.md
new file mode 100644
index 0000000..467759f
--- /dev/null
+++ b/contao/assets/chartjs/docs/developers/plugins.md
@@ -0,0 +1,128 @@
+# Plugins
+
+Plugins are the most efficient way to customize or change the default behavior of a chart. They have been introduced at [version 2.1.0](https://github.com/chartjs/Chart.js/releases/tag/2.1.0) (global plugins only) and extended at [version 2.5.0](https://github.com/chartjs/Chart.js/releases/tag/2.5.0) (per chart plugins and options).
+
+## Using plugins
+
+Plugins can be shared between chart instances:
+
+```javascript
+var plugin = { /* plugin implementation */ };
+
+// chart1 and chart2 use "plugin"
+var chart1 = new Chart(ctx, {
+ plugins: [plugin]
+});
+
+var chart2 = new Chart(ctx, {
+ plugins: [plugin]
+});
+
+// chart3 doesn't use "plugin"
+var chart3 = new Chart(ctx, {});
+```
+
+Plugins can also be defined directly in the chart `plugins` config (a.k.a. *inline plugins*):
+
+```javascript
+var chart = new Chart(ctx, {
+ plugins: [{
+ beforeInit: function(chart, options) {
+ //..
+ }
+ }]
+});
+```
+
+However, this approach is not ideal when the customization needs to apply to many charts.
+
+## Global plugins
+
+Plugins can be registered globally to be applied on all charts (a.k.a. *global plugins*):
+
+```javascript
+Chart.plugins.register({
+ // plugin implementation
+});
+```
+
+> Note: *inline* plugins can't be registered globally.
+
+## Configuration
+
+### Plugin ID
+
+Plugins must define a unique id in order to be configurable.
+
+This id should follow the [npm package name convention](https://docs.npmjs.com/files/package.json#name):
+
+- can't start with a dot or an underscore
+- can't contain any non-URL-safe characters
+- can't contain uppercase letters
+- should be something short, but also reasonably descriptive
+
+If a plugin is intended to be released publicly, you may want to check the [registry](https://www.npmjs.com/search?q=chartjs-plugin-) to see if there's something by that name already. Note that in this case, the package name should be prefixed by `chartjs-plugin-` to appear in Chart.js plugin registry.
+
+### Plugin options
+
+Plugin options are located under the `options.plugins` config and are scoped by the plugin ID: `options.plugins.{plugin-id}`.
+
+```javascript
+var chart = new Chart(ctx, {
+ config: {
+ foo: { ... }, // chart 'foo' option
+ plugins: {
+ p1: {
+ foo: { ... }, // p1 plugin 'foo' option
+ bar: { ... }
+ },
+ p2: {
+ foo: { ... }, // p2 plugin 'foo' option
+ bla: { ... }
+ }
+ }
+ }
+});
+```
+
+#### Disable plugins
+
+To disable a global plugin for a specific chart instance, the plugin options must be set to `false`:
+
+```javascript
+Chart.plugins.register({
+ id: 'p1',
+ // ...
+});
+
+var chart = new Chart(ctx, {
+ config: {
+ plugins: {
+ p1: false // disable plugin 'p1' for this instance
+ }
+ }
+});
+```
+
+## Plugin Core API
+
+Available hooks (as of version 2.5):
+
+* beforeInit
+* afterInit
+* beforeUpdate *(cancellable)*
+* afterUpdate
+* beforeLayout *(cancellable)*
+* afterLayout
+* beforeDatasetsUpdate *(cancellable)*
+* afterDatasetsUpdate
+* beforeRender *(cancellable)*
+* afterRender
+* beforeDraw *(cancellable)*
+* afterDraw
+* beforeDatasetsDraw *(cancellable)*
+* afterDatasetsDraw
+* beforeEvent *(cancellable)*
+* afterEvent
+* resize
+* destroy
diff --git a/contao/assets/chartjs/docs/developers/updates.md b/contao/assets/chartjs/docs/developers/updates.md
new file mode 100644
index 0000000..06550ce
--- /dev/null
+++ b/contao/assets/chartjs/docs/developers/updates.md
@@ -0,0 +1,31 @@
+# Updating Charts
+
+It's pretty common to want to update charts after they've been created. When the chart data is changed, Chart.js will animate to the new data values.
+
+## Adding or Removing Data
+
+Adding and removing data is supported by changing the data array. To add data, just add data into the data array as seen in this example.
+
+```javascript
+function addData(chart, label, data) {
+ chart.data.labels.push(label);
+ chart.data.datasets.forEach((dataset) => {
+ dataset.data.push(data);
+ });
+ chart.update();
+}
+```
+
+```javascript
+function removeData(chart) {
+ chart.data.labels.pop();
+ chart.data.datasets.forEach((dataset) => {
+ dataset.data.pop();
+ });
+ chart.update();
+}
+```
+
+## Preventing Animations
+
+Sometimes when a chart updates, you may not want an animation. To achieve this you can call `update` with a duration of `0`. This will render the chart synchronously and without an animation.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/general/README.md b/contao/assets/chartjs/docs/general/README.md
new file mode 100644
index 0000000..f075bca
--- /dev/null
+++ b/contao/assets/chartjs/docs/general/README.md
@@ -0,0 +1,8 @@
+# General Chart.js Configuration
+
+These sections describe general configuration options that can apply elsewhere in the documentation.
+
+* [Colors](./colors.md) defines acceptable color values
+* [Font](./fonts.md) defines various font options
+* [Interactions](./interactions/README.md) defines options that reflect how hovering chart elements works
+* [Responsive](./responsive.md) defines responsive chart options that apply to all charts.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/general/colors.md b/contao/assets/chartjs/docs/general/colors.md
new file mode 100644
index 0000000..d2d2700
--- /dev/null
+++ b/contao/assets/chartjs/docs/general/colors.md
@@ -0,0 +1,49 @@
+# Colors
+
+When supplying colors to Chart options, you can use a number of formats. You can specify the color as a string in hexadecimal, RGB, or HSL notations. If a color is needed, but not specified, Chart.js will use the global default color. This color is stored at `Chart.defaults.global.defaultColor`. It is initially set to `'rgba(0, 0, 0, 0.1)'`
+
+You can also pass a [CanvasGradient](https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient) object. You will need to create this before passing to the chart, but using it you can achieve some interesting effects.
+
+## Patterns and Gradients
+
+An alternative option is to pass a [CanvasPattern](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern) or [CanvasGradient](https://developer.mozilla.org/en/docs/Web/API/CanvasGradient) object instead of a string colour.
+
+For example, if you wanted to fill a dataset with a pattern from an image you could do the following.
+
+```javascript
+var img = new Image();
+img.src = 'https://example.com/my_image.png';
+img.onload = function() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+ var fillPattern = ctx.createPattern(img, 'repeat');
+
+ var chart = new Chart(ctx, {
+ data: {
+ labels: ['Item 1', 'Item 2', 'Item 3'],
+ datasets: [{
+ data: [10, 20, 30],
+ backgroundColor: fillPattern
+ }]
+ }
+ })
+}
+```
+
+Using pattern fills for data graphics can help viewers with vision deficiencies (e.g. color-blindness or partial sight) to [more easily understand your data](http://betweentwobrackets.com/data-graphics-and-colour-vision/).
+
+Using the [Patternomaly](https://github.com/ashiguruma/patternomaly) library you can generate patterns to fill datasets.
+
+```javascript
+var chartData = {
+ datasets: [{
+ data: [45, 25, 20, 10],
+ backgroundColor: [
+ pattern.draw('square', '#ff6384'),
+ pattern.draw('circle', '#36a2eb'),
+ pattern.draw('diamond', '#cc65fe'),
+ pattern.draw('triangle', '#ffce56'),
+ ]
+ }],
+ labels: ['Red', 'Blue', 'Purple', 'Yellow']
+};
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/general/fonts.md b/contao/assets/chartjs/docs/general/fonts.md
new file mode 100644
index 0000000..dd47529
--- /dev/null
+++ b/contao/assets/chartjs/docs/general/fonts.md
@@ -0,0 +1,28 @@
+# Fonts
+
+There are 4 special global settings that can change all of the fonts on the chart. These options are in `Chart.defaults.global`. The global font settings only apply when more specific options are not included in the config.
+
+For example, in this chart the text will all be red except for the labels in the legend.
+
+```javascript
+Chart.defaults.global.defaultFontColor = 'red';
+let chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ legend: {
+ labels: {
+ // This more specific font property overrides the global property
+ fontColor: 'black'
+ }
+ }
+ }
+});
+```
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `defaultFontColor` | `Color` | `'#666'` | Default font color for all text.
+| `defaultFontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Default font family for all text.
+| `defaultFontSize` | `Number` | `12` | Default font size (in px) for text. Does not apply to radialLinear scale point labels.
+| `defaultFontStyle` | `String` | `'normal'` | Default font style. Does not apply to tooltip title or footer. Does not apply to chart title.
diff --git a/contao/assets/chartjs/docs/general/interactions/README.md b/contao/assets/chartjs/docs/general/interactions/README.md
new file mode 100644
index 0000000..1ff1d55
--- /dev/null
+++ b/contao/assets/chartjs/docs/general/interactions/README.md
@@ -0,0 +1,9 @@
+# Interactions
+
+The hover configuration is passed into the `options.hover` namespace. The global hover configuration is at `Chart.defaults.global.hover`. To configure which events trigger chart interactions, see [events](./events.md#events).
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `mode` | `String` | `'nearest'` | Sets which elements appear in the tooltip. See [Interaction Modes](./modes.md#interaction-modes) for details.
+| `intersect` | `Boolean` | `true` | if true, the hover mode only applies when the mouse position intersects an item on the chart.
+| `animationDuration` | `Number` | `400` | Duration in milliseconds it takes to animate hover style changes.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/general/interactions/events.md b/contao/assets/chartjs/docs/general/interactions/events.md
new file mode 100644
index 0000000..8e21f75
--- /dev/null
+++ b/contao/assets/chartjs/docs/general/interactions/events.md
@@ -0,0 +1,21 @@
+# Events
+The following properties define how the chart interacts with events.
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `events` | `String[]` | `["mousemove", "mouseout", "click", "touchstart", "touchmove", "touchend"]` | The `events` option defines the browser events that the chart should listen to for tooltips and hovering. [more...](#event-option)
+| `onHover` | `Function` | `null` | Called when any of the events fire. Called in the context of the chart and passed the event and an array of active elements (bars, points, etc).
+| `onClick` | `Function` | `null` | Called if the event is of type 'mouseup' or 'click'. Called in the context of the chart and passed the event and an array of active elements
+
+## Event Option
+For example, to have the chart only respond to click events, you could do
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ // This chart will not respond to mousemove, etc
+ events: ['click']
+ }
+});
+```
diff --git a/contao/assets/chartjs/docs/general/interactions/modes.md b/contao/assets/chartjs/docs/general/interactions/modes.md
new file mode 100644
index 0000000..6775c59
--- /dev/null
+++ b/contao/assets/chartjs/docs/general/interactions/modes.md
@@ -0,0 +1,104 @@
+# Interaction Modes
+
+When configuring interaction with the graph via hover or tooltips, a number of different modes are available.
+
+The modes are detailed below and how they behave in conjunction with the `intersect` setting.
+
+## point
+Finds all of the items that intersect the point.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ tooltips: {
+ mode: 'point'
+ }
+ }
+})
+```
+
+## nearest
+Gets the item that is nearest to the point. The nearest item is determined based on the distance to the center of the chart item (point, bar). If 2 or more items are at the same distance, the one with the smallest area is used. If `intersect` is true, this is only triggered when the mouse position intersects an item in the graph. This is very useful for combo charts where points are hidden behind bars.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ tooltips: {
+ mode: 'nearest'
+ }
+ }
+})
+```
+
+## single (deprecated)
+Finds the first item that intersects the point and returns it. Behaves like 'nearest' mode with intersect = true.
+
+## label (deprecated)
+See `'index'` mode
+
+## index
+Finds item at the same index. If the `intersect` setting is true, the first intersecting item is used to determine the index in the data. If `intersect` false the nearest item is used to determine the index.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ tooltips: {
+ mode: 'index'
+ }
+ }
+})
+```
+
+## x-axis (deprecated)
+Behaves like `'index'` mode with `intersect = false`.
+
+## dataset
+Finds items in the same dataset. If the `intersect` setting is true, the first intersecting item is used to determine the index in the data. If `intersect` false the nearest item is used to determine the index.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ tooltips: {
+ mode: 'dataset'
+ }
+ }
+})
+```
+
+## x
+Returns all items that would intersect based on the `X` coordinate of the position only. Would be useful for a vertical cursor implementation. Note that this only applies to cartesian charts
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ tooltips: {
+ mode: 'x'
+ }
+ }
+})
+```
+
+## y
+Returns all items that would intersect based on the `Y` coordinate of the position. This would be useful for a horizontal cursor implementation. Note that this only applies to cartesian charts.
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ tooltips: {
+ mode: 'y'
+ }
+ }
+})
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/general/responsive.md b/contao/assets/chartjs/docs/general/responsive.md
new file mode 100644
index 0000000..bf8e8fa
--- /dev/null
+++ b/contao/assets/chartjs/docs/general/responsive.md
@@ -0,0 +1,35 @@
+# Responsive Charts
+
+When it comes to change the chart size based on the window size, a major limitation is that the canvas *render* size (`canvas.width` and `.height`) can **not** be expressed with relative values, contrary to the *display* size (`canvas.style.width` and `.height`). Furthermore, these sizes are independent from each other and thus the canvas *render* size does not adjust automatically based on the *display* size, making the rendering inaccurate.
+
+The following examples **do not work**:
+
+- ``: **invalid** values, the canvas doesn't resize ([example](https://codepen.io/chartjs/pen/oWLZaR))
+- ``: **invalid** behavior, the canvas is resized but becomes blurry ([example](https://codepen.io/chartjs/pen/WjxpmO))
+
+Chart.js provides a [few options](#configuration-options) to enable responsiveness and control the resize behavior of charts by detecting when the canvas *display* size changes and update the *render* size accordingly.
+
+## Configuration Options
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `responsive` | `Boolean` | `true` | Resizes the chart canvas when its container does ([important note...](#important-note)).
+| `responsiveAnimationDuration` | `Number` | `0` | Duration in milliseconds it takes to animate to new size after a resize event.
+| `maintainAspectRatio` | `Boolean` | `true` | Maintain the original canvas aspect ratio `(width / height)` when resizing.
+| `onResize` | `Function` | `null` | Called when a resize occurs. Gets passed two arguments: the chart instance and the new size.
+
+## Important Note
+
+Detecting when the canvas size changes can not be done directly from the `CANVAS` element. Chart.js uses its parent container to update the canvas *render* and *display* sizes. However, this method requires the container to be **relatively positioned** and **dedicated to the chart canvas only**. Responsiveness can then be achieved by setting relative values for the container size ([example](https://codepen.io/chartjs/pen/YVWZbz)):
+
+```html
+
+
+
+```
+
+The chart can also be programmatically resized by modifying the container size:
+
+```javascript
+chart.canvas.parentNode.style.height = '128px';
+```
diff --git a/contao/assets/chartjs/docs/getting-started/README.md b/contao/assets/chartjs/docs/getting-started/README.md
new file mode 100644
index 0000000..bb3e17f
--- /dev/null
+++ b/contao/assets/chartjs/docs/getting-started/README.md
@@ -0,0 +1,43 @@
+# Getting Started
+
+Let's get started using Chart.js!
+
+First, we need to have a canvas in our page.
+
+```html
+
+```
+
+Now that we have a canvas we can use, we need to include Chart.js in our page.
+
+```html
+
+```
+
+Now, we can create a chart. We add a script to our page:
+
+```javascript
+var ctx = document.getElementById('myChart').getContext('2d');
+var chart = new Chart(ctx, {
+ // The type of chart we want to create
+ type: 'line',
+
+ // The data for our dataset
+ data: {
+ labels: ["January", "February", "March", "April", "May", "June", "July"],
+ datasets: [{
+ label: "My First dataset",
+ backgroundColor: 'rgb(255, 99, 132)',
+ borderColor: 'rgb(255, 99, 132)',
+ data: [0, 10, 5, 2, 20, 30, 45],
+ }]
+ },
+
+ // Configuration options go here
+ options: {}
+});
+```
+
+It's that easy to get started using Chart.js! From here you can explore the many options that can help you customise your charts with scales, tooltips, labels, colors, custom actions, and much more.
+
+There are many examples of Chart.js that are available in the `/samples` folder of `Chart.js.zip` that is attatched to every [release](https://github.com/chartjs/Chart.js/releases).
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/getting-started/installation.md b/contao/assets/chartjs/docs/getting-started/installation.md
new file mode 100644
index 0000000..4a3df6e
--- /dev/null
+++ b/contao/assets/chartjs/docs/getting-started/installation.md
@@ -0,0 +1,41 @@
+# Installation
+Chart.js can be installed via npm or bower. It is recommended to get Chart.js this way.
+
+## npm
+
+```bash
+npm install chart.js --save
+```
+
+## Bower
+
+```bash
+bower install chart.js --save
+```
+
+## CDN
+or just use these [Chart.js CDN](https://cdnjs.com/libraries/Chart.js) links.
+
+
+## Github
+You can download the latest version of [Chart.js on GitHub](https://github.com/chartjs/Chart.js/releases/latest).
+
+If you download or clone the repository, you must [build](../developers/contributing.md#building-chartjs) Chart.js to generate the dist files. Chart.js no longer comes with prebuilt release versions, so an alternative option to downloading the repo is **strongly** advised.
+
+# Selecting the Correct Build
+
+Chart.js provides two different builds that are available for your use.
+
+## Stand-Alone Build
+Files:
+* `dist/Chart.js`
+* `dist/Chart.min.js`
+
+This version only includes Chart.js. If this version is used and you require the use of the time axis, [Moment.js](http://momentjs.com/) will need to be included before Chart.js.
+
+## Bundled Build
+Files:
+* `dist/Chart.bundle.js`
+* `dist/Chart.bundle.min.js`
+
+The bundled version includes Moment.js built into the same file. This version should be used if you wish to use time axes and want a single file to include. Do not use this build if your application already includes Moment.js. If you do, Moment.js will be included twice, increasing the page load time and potentially introducing version issues.
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/getting-started/integration.md b/contao/assets/chartjs/docs/getting-started/integration.md
new file mode 100644
index 0000000..173448f
--- /dev/null
+++ b/contao/assets/chartjs/docs/getting-started/integration.md
@@ -0,0 +1,36 @@
+# Integration
+
+Chart.js can be integrated with plain JavaScript or with different module loaders. The examples below show how to load Chart.js in different systems.
+
+## ES6 Modules
+
+```javascript
+import Chart from 'chart.js';
+var myChart = new Chart(ctx, {...});
+```
+
+## Script Tag
+
+```html
+
+
+```
+
+## Common JS
+
+```javascript
+var Chart = require('chart.js');
+var myChart = new Chart(ctx, {...});
+```
+
+## Require JS
+
+```javascript
+require(['path/to/chartjs/dist/Chart.js'], function(Chart){
+ var myChart = new Chart(ctx, {...});
+});
+```
+
+> **Important:** RequireJS [can **not** load CommonJS module as is](http://www.requirejs.org/docs/commonjs.html#intro), so be sure to require one of the built UMD files instead (i.e. `dist/Chart.js`, `dist/Chart.min.js`, etc.).
diff --git a/contao/assets/chartjs/docs/getting-started/usage.md b/contao/assets/chartjs/docs/getting-started/usage.md
new file mode 100644
index 0000000..739c838
--- /dev/null
+++ b/contao/assets/chartjs/docs/getting-started/usage.md
@@ -0,0 +1,65 @@
+# Usage
+Chart.js can be used with ES6 modules, plain JavaScript and module loaders.
+
+## Creating a Chart
+
+To create a chart, we need to instantiate the `Chart` class. To do this, we need to pass in the node, jQuery instance, or 2d context of the canvas of where we want to draw the chart. Here's an example.
+
+```html
+
+```
+
+```javascript
+// Any of the following formats may be used
+var ctx = document.getElementById("myChart");
+var ctx = document.getElementById("myChart").getContext("2d");
+var ctx = $("#myChart");
+var ctx = "myChart";
+```
+
+Once you have the element or context, you're ready to instantiate a pre-defined chart-type or create your own!
+
+The following example instantiates a bar chart showing the number of votes for different colors and the y-axis starting at 0.
+
+```html
+
+
+```
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/notes/README.md b/contao/assets/chartjs/docs/notes/README.md
new file mode 100644
index 0000000..2795fae
--- /dev/null
+++ b/contao/assets/chartjs/docs/notes/README.md
@@ -0,0 +1 @@
+# Additional Notes
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/notes/comparison.md b/contao/assets/chartjs/docs/notes/comparison.md
new file mode 100644
index 0000000..aa7e25e
--- /dev/null
+++ b/contao/assets/chartjs/docs/notes/comparison.md
@@ -0,0 +1,32 @@
+# Comparison with Other Charting Libraries
+
+Library Features
+
+| Feature | Chart.js | D3 | HighCharts | Chartist |
+| ------- | -------- | --- | ---------- | -------- |
+| Completely Free | ✓ | ✓ | | ✓ |
+| Canvas | ✓ | | | |
+| SVG | | ✓ | ✓ | ✓ |
+| Built-in Charts | ✓ | | ✓ | ✓ |
+| 8+ Chart Types | ✓ | ✓ | ✓ | |
+| Extendable to Custom Charts | ✓ | ✓ | | |
+| Supports Modern Browsers | ✓ | ✓ | ✓ | ✓ |
+| Extensive Documentation | ✓ | ✓ | ✓ | ✓ |
+| Open Source | ✓ | ✓ | ✓ | ✓ |
+
+Built in Chart Types
+
+| Type | Chart.js | HighCharts | Chartist |
+| ---- | -------- | ---------- | -------- |
+| Combined Types | ✓ | ✓ | |
+| Line | ✓ | ✓ | ✓ |
+| Bar | ✓ | ✓ | ✓ |
+| Horizontal Bar | ✓ | ✓ | ✓ |
+| Pie/Doughnut | ✓ | ✓ | ✓ |
+| Polar Area | ✓ | ✓ | |
+| Radar | ✓ | | |
+| Scatter | ✓ | ✓ | ✓ |
+| Bubble | ✓ | | |
+| Gauges | | ✓ | |
+| Maps (Heat/Tree/etc.) | | ✓ | |
+
diff --git a/contao/assets/chartjs/docs/notes/extensions.md b/contao/assets/chartjs/docs/notes/extensions.md
new file mode 100644
index 0000000..4399110
--- /dev/null
+++ b/contao/assets/chartjs/docs/notes/extensions.md
@@ -0,0 +1,47 @@
+# Popular Extensions
+
+Many extensions can be found on the [Chart.js GitHub organization](https://github.com/chartjs) or on the [npm registry](https://www.npmjs.com/search?q=chartjs-).
+
+## Charts
+
+ - chartjs-chart-financial - Adds financial chart types such as a candlestick.
+ - Chart.BarFunnel.js - Adds a bar funnel chart type.
+ - Chart.LinearGauge.js - Adds a linear gauge chart type.
+ - Chart.Smith.js - Adds a smith chart type.
+
+In addition, many charts can be found on the [npm registry](https://www.npmjs.com/search?q=chartjs-chart-).
+
+## Plugins
+
+ - chartjs-plugin-annotation.js - Draw lines and boxes on chart area.
+ - chartjs-plugin-deferred.js - Defer initial chart update until chart scrolls into viewport.
+ - chartjs-plugin-draggable.js - Makes select chart elements draggable with the mouse.
+ - chartjs-plugin-stacked100.js - Draw 100% stacked bar chart.
+ - chartjs-plugin-zoom.js - Enable zooming and panning on charts.
+
+In addition, many plugins can be found on the [npm registry](https://www.npmjs.com/search?q=chartjs-plugin-).
+
+## Integrations
+
+### Angular
+ - angular-chart.js
+ - tc-angular-chartjs
+ - angular-chartjs
+ - Angular Chart-js Directive
+
+### React
+ - react-chartjs2
+ - react-chartjs-2
+
+### Django
+ - Django JChart
+ - Django Chartjs
+
+### Ruby on Rails
+ - chartjs-ror
+
+### Laravel
+ - laravel-chartjs
+
+### Vue.js
+ - vue-chartjs
diff --git a/contao/assets/chartjs/docs/notes/license.md b/contao/assets/chartjs/docs/notes/license.md
new file mode 100644
index 0000000..b933686
--- /dev/null
+++ b/contao/assets/chartjs/docs/notes/license.md
@@ -0,0 +1,3 @@
+# License
+
+Chart.js is open source and available under the MIT license .
\ No newline at end of file
diff --git a/contao/assets/chartjs/docs/style.css b/contao/assets/chartjs/docs/style.css
new file mode 100644
index 0000000..acdd3e5
--- /dev/null
+++ b/contao/assets/chartjs/docs/style.css
@@ -0,0 +1,15 @@
+a.anchorjs-link {
+ color: rgba(65, 131, 196, 0.1);
+ font-weight: 400;
+ text-decoration: none;
+ transition: color 100ms ease-out;
+ z-index: 999;
+}
+
+a.anchorjs-link:hover {
+ color: rgba(65, 131, 196, 1);
+}
+
+sup {
+ font-size: 0.75em !important;
+}
diff --git a/contao/assets/chartjs/gulpfile.js b/contao/assets/chartjs/gulpfile.js
index 1ce312d..884242f 100644
--- a/contao/assets/chartjs/gulpfile.js
+++ b/contao/assets/chartjs/gulpfile.js
@@ -11,13 +11,14 @@ var streamify = require('gulp-streamify');
var uglify = require('gulp-uglify');
var util = require('gulp-util');
var zip = require('gulp-zip');
-var exec = require('child_process').exec;
-var karma = require('gulp-karma');
+var exec = require('child-process-promise').exec;
+var karma = require('karma');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var merge = require('merge-stream');
var collapse = require('bundle-collapser/plugin');
var argv = require('yargs').argv
+var path = require('path');
var package = require('./package.json');
var srcDir = './src/';
@@ -29,31 +30,22 @@ var header = "/*!\n" +
" * http://chartjs.org/\n" +
" * Version: {{ version }}\n" +
" *\n" +
- " * Copyright 2016 Nick Downie\n" +
+ " * Copyright 2017 Nick Downie\n" +
" * Released under the MIT license\n" +
" * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md\n" +
" */\n";
-var preTestFiles = [
- './node_modules/moment/min/moment.min.js'
-];
-
-var testFiles = [
- './test/*.js'
-];
-
gulp.task('bower', bowerTask);
gulp.task('build', buildTask);
gulp.task('package', packageTask);
-gulp.task('coverage', coverageTask);
gulp.task('watch', watchTask);
gulp.task('lint', lintTask);
+gulp.task('docs', docsTask);
gulp.task('test', ['lint', 'validHTML', 'unittest']);
gulp.task('size', ['library-size', 'module-sizes']);
gulp.task('server', serverTask);
gulp.task('validHTML', validHTMLTask);
gulp.task('unittest', unittestTask);
-gulp.task('unittestWatch', unittestWatchTask);
gulp.task('library-size', librarySizeTask);
gulp.task('module-sizes', moduleSizesTask);
gulp.task('_open', _openTask);
@@ -71,7 +63,15 @@ function bowerTask() {
homepage: package.homepage,
license: package.license,
version: package.version,
- main: outDir + "Chart.js"
+ main: outDir + "Chart.js",
+ ignore: [
+ '.github',
+ '.codeclimate.yml',
+ '.gitignore',
+ '.npmignore',
+ '.travis.yml',
+ 'scripts'
+ ]
}, null, 2);
return file('bower.json', json, { src: true })
@@ -149,6 +149,7 @@ function lintTask() {
'beforeEach',
'describe',
'expect',
+ 'fail',
'it',
'jasmine',
'moment',
@@ -163,43 +164,47 @@ function lintTask() {
.pipe(eslint.failAfterError());
}
+function docsTask(done) {
+ const script = require.resolve('gitbook-cli/bin/gitbook.js');
+ const cmd = process.execPath;
+
+ exec([cmd, script, 'install', './'].join(' ')).then(() => {
+ return exec([cmd, script, 'build', './', './dist/docs'].join(' '));
+ }).catch((err) => {
+ console.error(err.stdout);
+ }).then(() => {
+ done();
+ });
+}
+
function validHTMLTask() {
return gulp.src('samples/*.html')
.pipe(htmlv());
}
function startTest() {
- return [].concat(preTestFiles).concat([
- './src/**/*.js',
- './test/mockContext.js'
- ]).concat(
- argv.inputs?
- argv.inputs.split(';'):
- testFiles);
+ return [
+ {pattern: './test/fixtures/**/*.json', included: false},
+ {pattern: './test/fixtures/**/*.png', included: false},
+ './node_modules/moment/min/moment.min.js',
+ './test/jasmine.index.js',
+ './src/**/*.js',
+ ].concat(
+ argv.inputs?
+ argv.inputs.split(';'):
+ ['./test/specs/**/*.js']
+ );
}
-function unittestTask() {
- return gulp.src(startTest())
- .pipe(karma({
- configFile: 'karma.conf.ci.js',
- action: 'run'
- }));
-}
-
-function unittestWatchTask() {
- return gulp.src(startTest())
- .pipe(karma({
- configFile: 'karma.conf.js',
- action: 'watch'
- }));
-}
-
-function coverageTask() {
- return gulp.src(startTest())
- .pipe(karma({
- configFile: 'karma.coverage.conf.js',
- action: 'run'
- }));
+function unittestTask(done) {
+ new karma.Server({
+ configFile: path.join(__dirname, 'karma.conf.js'),
+ singleRun: !argv.watch,
+ files: startTest(),
+ args: {
+ coverage: !!argv.coverage
+ }
+ }, done).start();
}
function librarySizeTask() {
diff --git a/contao/assets/chartjs/karma.conf.ci.js b/contao/assets/chartjs/karma.conf.ci.js
deleted file mode 100644
index 7ed5d0f..0000000
--- a/contao/assets/chartjs/karma.conf.ci.js
+++ /dev/null
@@ -1,25 +0,0 @@
-module.exports = function(config) {
- var configuration = {
- browsers: ['Firefox'],
- customLaunchers: {
- Chrome_travis_ci: {
- base: 'Chrome',
- flags: ['--no-sandbox']
- }
- },
- frameworks: ['browserify', 'jasmine'],
- reporters: ['progress', 'html'],
- preprocessors: {
- 'src/**/*.js': ['browserify']
- },
- browserify: {
- debug: true
- }
- };
-
- if (process.env.TRAVIS) {
- configuration.browsers.push('Chrome_travis_ci');
- }
-
- config.set(configuration);
-};
\ No newline at end of file
diff --git a/contao/assets/chartjs/karma.conf.js b/contao/assets/chartjs/karma.conf.js
index acdff3f..3ef7f49 100644
--- a/contao/assets/chartjs/karma.conf.js
+++ b/contao/assets/chartjs/karma.conf.js
@@ -1,14 +1,48 @@
-module.exports = function(config) {
- config.set({
- browsers: ['Chrome', 'Firefox'],
+/* eslint camelcase: 0 */
+
+module.exports = function(karma) {
+ var args = karma.args || {};
+ var config = {
+ browsers: ['Firefox'],
frameworks: ['browserify', 'jasmine'],
- reporters: ['progress', 'html'],
+ reporters: ['progress', 'kjhtml'],
preprocessors: {
- 'src/**/*.js': ['browserify']
+ './test/jasmine.index.js': ['browserify'],
+ './src/**/*.js': ['browserify']
},
+
browserify: {
debug: true
}
- });
-};
\ No newline at end of file
+ };
+
+ // https://swizec.com/blog/how-to-run-javascript-tests-in-chrome-on-travis/swizec/6647
+ if (process.env.TRAVIS) {
+ config.browsers.push('chrome_travis_ci');
+ config.customLaunchers = {
+ chrome_travis_ci: {
+ base: 'Chrome',
+ flags: ['--no-sandbox']
+ }
+ };
+ } else {
+ config.browsers.push('Chrome');
+ }
+
+ if (args.coverage) {
+ config.reporters.push('coverage');
+ config.browserify.transform = ['browserify-istanbul'];
+
+ // https://github.com/karma-runner/karma-coverage/blob/master/docs/configuration.md
+ config.coverageReporter = {
+ dir: 'coverage/',
+ reporters: [
+ {type: 'html', subdir: 'report-html'},
+ {type: 'lcovonly', subdir: '.', file: 'lcov.info'}
+ ]
+ };
+ }
+
+ karma.set(config);
+};
diff --git a/contao/assets/chartjs/karma.coverage.conf.js b/contao/assets/chartjs/karma.coverage.conf.js
deleted file mode 100644
index dd70f70..0000000
--- a/contao/assets/chartjs/karma.coverage.conf.js
+++ /dev/null
@@ -1,43 +0,0 @@
-module.exports = function(config) {
- var configuration = {
- browsers: ['Firefox'],
-
- frameworks: ['browserify', 'jasmine'],
-
- preprocessors: {
- 'src/**/*.js': ['browserify']
- },
- browserify: {
- debug: true,
- transform: [['browserify-istanbul', {
- instrumenterConfig: {
- embed: true
- }
- }]]
- },
-
- reporters: ['progress', 'coverage'],
- coverageReporter: {
- dir: 'coverage/',
- reporters: [
- { type: 'html', subdir: 'report-html' },
- { type: 'lcovonly', subdir: '.', file: 'lcov.info' }
- ]
- }
- };
-
- // If on the CI, use the CI chrome launcher
- if (process.env.TRAVIS) {
- configuration.browsers.push('Chrome_travis_ci');
- configuration.customLaunchers = {
- Chrome_travis_ci: {
- base: 'Chrome',
- flags: ['--no-sandbox']
- }
- };
- } else {
- configuration.browsers.push('Chrome');
- }
-
- config.set(configuration);
-};
\ No newline at end of file
diff --git a/contao/assets/chartjs/package.json b/contao/assets/chartjs/package.json
index b8dba18..7963c6e 100644
--- a/contao/assets/chartjs/package.json
+++ b/contao/assets/chartjs/package.json
@@ -2,7 +2,7 @@
"name": "chart.js",
"homepage": "http://www.chartjs.org",
"description": "Simple HTML5 charts using the canvas element.",
- "version": "2.4.0",
+ "version": "2.6.0",
"license": "MIT",
"main": "src/chart.js",
"repository": {
@@ -13,7 +13,9 @@
"browserify": "^13.0.0",
"browserify-istanbul": "^0.2.1",
"bundle-collapser": "^1.2.1",
+ "child-process-promise": "^2.2.0",
"coveralls": "^2.11.6",
+ "gitbook-cli": "^2.3.0",
"gulp": "3.9.x",
"gulp-concat": "~2.1.x",
"gulp-connect": "~2.0.5",
@@ -21,23 +23,23 @@
"gulp-file": "^0.3.0",
"gulp-html-validator": "^0.0.2",
"gulp-insert": "~0.5.0",
- "gulp-karma": "0.0.4",
"gulp-replace": "^0.5.4",
"gulp-size": "~0.4.0",
"gulp-streamify": "^1.0.2",
- "gulp-uglify": "~0.2.x",
+ "gulp-uglify": "~2.0.x",
"gulp-util": "~2.2.x",
"gulp-zip": "~3.2.0",
- "jasmine": "^2.3.2",
- "jasmine-core": "^2.3.4",
- "karma": "^0.12.37",
- "karma-browserify": "^5.0.1",
- "karma-chrome-launcher": "^0.2.0",
- "karma-coverage": "^0.5.1",
- "karma-firefox-launcher": "^0.1.6",
- "karma-jasmine": "^0.3.6",
- "karma-jasmine-html-reporter": "^0.1.8",
+ "jasmine": "^2.5.0",
+ "jasmine-core": "^2.5.0",
+ "karma": "^1.5.0",
+ "karma-browserify": "^5.1.0",
+ "karma-chrome-launcher": "^2.0.0",
+ "karma-coverage": "^1.1.0",
+ "karma-firefox-launcher": "^1.0.0",
+ "karma-jasmine": "^1.1.0",
+ "karma-jasmine-html-reporter": "^0.2.2",
"merge-stream": "^1.0.0",
+ "pixelmatch": "^4.0.2",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.7.0",
"yargs": "^5.0.0"
@@ -46,7 +48,7 @@
"main": "Chart.js"
},
"dependencies": {
- "chartjs-color": "^2.0.0",
+ "chartjs-color": "^2.1.0",
"moment": "^2.10.6"
}
}
diff --git a/contao/assets/chartjs/samples/data_labelling.html b/contao/assets/chartjs/samples/advanced/data-labelling.html
similarity index 77%
rename from contao/assets/chartjs/samples/data_labelling.html
rename to contao/assets/chartjs/samples/advanced/data-labelling.html
index 939e517..17fc47c 100644
--- a/contao/assets/chartjs/samples/data_labelling.html
+++ b/contao/assets/chartjs/samples/advanced/data-labelling.html
@@ -4,8 +4,8 @@
Labelling Data Points
-
-
+
+
+
+
+
+
+
+
+ Randomize Data
+
+
+
+